我正在处理大量的对象(POI),这些对象会显示在一个地图控件上。我使用MVVM Light来遵循MVVM方法的规则。
由于我必须在地图上显示每个对象,所以我必须使用MapItemsControl集合,而不是MapElements集合。该集合绑定到相应ViewModel中的ObservableCollection 对象(Pushpins)。一切都按预期工作,直到我想要刷新Pushpins。问题是内存泄漏。但首先,让我们看一下代码来可视化问题:
XAML:
现在考虑以下情况。我向“Pushpins”集合中添加了1000个“PushpinViewModel”元素并进行了渲染,分配了内存,一切都很好。现在我想清除该集合,并添加其他(在实际情况下不同的)1000个元素。所以,我调用了“Clear()”方法。但是...什么也没发生!“Pushpins”被清除了,但“PushpinViewModel”的终结器没有被调用!然后我再次添加了1000个元素,我的内存使用量加倍了。
你可以猜到接下来会发生什么。当我重复执行此“Clear()” - “Add()”过程3-5次时,我的应用程序崩溃了。
那么问题出在哪里呢?显然,“ObservableCollection”在对其执行“Clear()”操作后保持对“PushpinViewModel”对象的引用,因此它们无法进行垃圾回收。当然,强制GC执行垃圾回收没有帮助(有时甚至会使情况变得更糟)。
这让我困扰了2天,我尝试了许多不同的场景来尝试克服这个问题,但说实话,没有什么帮助。只有一件值得注意的事情——我不记得确切的情况了,但当我分配“Pushpins=null”,然后做了一些其他事情时,“VehiceViewModel”被销毁了。但这对我来说行不通,因为我也记得在“Clear()”之后视觉上无法在地图上显示这些引脚。
你有任何想法是什么导致了这个内存泄漏吗?我如何强制“OC”的成员销毁?也许有一种替代“OC”的方法?
提前感谢任何帮助!
编辑:
我进行了一些XAML地图控制的测试-https://xamlmapcontrol.codeplex.com/,结果令人惊讶。总体而言,添加了超过1000个元素的地图性能比本机“MapControl”差,但是,如果我调用“Add()”x1000,然后“Clear()”,然后“Add()”x1000,“PushpinViewModel”的终结器就会被调用!内存被释放,应用程序不会崩溃。因此,微软的“MapControl”肯定存在问题...
由于我必须在地图上显示每个对象,所以我必须使用MapItemsControl集合,而不是MapElements集合。该集合绑定到相应ViewModel中的ObservableCollection 对象(Pushpins)。一切都按预期工作,直到我想要刷新Pushpins。问题是内存泄漏。但首先,让我们看一下代码来可视化问题:
XAML:
<maps:MapControl x:Name="Map"
x:Uid="MapControl">
<maps:MapItemsControl ItemsSource="{Binding Pushpins}">
<maps:MapItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Image}"/>
</DataTemplate>
</maps:MapItemsControl.ItemTemplate>
</maps:MapItemsControl>
MainViewModel:
public class MainViewModel : ViewModelBase
{
public RelayCommand AddCommand { get; set; }
public RelayCommand ClearCommand { get; set; }
public RelayCommand CollectCommand { get; set; }
public ObservableCollection<PushpinViewModel> Pushpins { get; set; }
/* Ctor, initialization of Pushpins and stuff like that */
private void Collect()
{
GC.Collect(2);
GC.WaitForPendingFinalizers();
GC.Collect(2);
PrintCurrentMemory();
}
private void Clear()
{
Pushpins.Clear();
PrintCurrentMemory();
}
private void Add()
{
for (int i = 0; i < 1000; i++)
{
Pushpins.Add(new PushpinViewModel());
}
PrintCurrentMemory();
}
private void PrintCurrentMemory()
{
Logger.Log(String.Format("Total Memory: {0}", GC.GetTotalMemory(true) / 1024.0));
}
}
PushpinViewModel:
public class PushpinViewModel: ViewModelBase
{
public string Image { get { return "/Assets/SomeImage.png"; } }
~PushpinViewModel()
{
Logger.Log("This finalizer never gets called!");
}
}
现在考虑以下情况。我向“Pushpins”集合中添加了1000个“PushpinViewModel”元素并进行了渲染,分配了内存,一切都很好。现在我想清除该集合,并添加其他(在实际情况下不同的)1000个元素。所以,我调用了“Clear()”方法。但是...什么也没发生!“Pushpins”被清除了,但“PushpinViewModel”的终结器没有被调用!然后我再次添加了1000个元素,我的内存使用量加倍了。
你可以猜到接下来会发生什么。当我重复执行此“Clear()” - “Add()”过程3-5次时,我的应用程序崩溃了。
那么问题出在哪里呢?显然,“ObservableCollection”在对其执行“Clear()”操作后保持对“PushpinViewModel”对象的引用,因此它们无法进行垃圾回收。当然,强制GC执行垃圾回收没有帮助(有时甚至会使情况变得更糟)。
这让我困扰了2天,我尝试了许多不同的场景来尝试克服这个问题,但说实话,没有什么帮助。只有一件值得注意的事情——我不记得确切的情况了,但当我分配“Pushpins=null”,然后做了一些其他事情时,“VehiceViewModel”被销毁了。但这对我来说行不通,因为我也记得在“Clear()”之后视觉上无法在地图上显示这些引脚。
你有任何想法是什么导致了这个内存泄漏吗?我如何强制“OC”的成员销毁?也许有一种替代“OC”的方法?
提前感谢任何帮助!
编辑:
我进行了一些XAML地图控制的测试-https://xamlmapcontrol.codeplex.com/,结果令人惊讶。总体而言,添加了超过1000个元素的地图性能比本机“MapControl”差,但是,如果我调用“Add()”x1000,然后“Clear()”,然后“Add()”x1000,“PushpinViewModel”的终结器就会被调用!内存被释放,应用程序不会崩溃。因此,微软的“MapControl”肯定存在问题...