【发布时间】:2014-11-29 07:46:48
【问题描述】:
我正在处理大量显示在 MapControl 上的对象 (POI)。我正在使用 MVVM Light 帮助自己遵守 MVVM 方法的规则。
由于我有义务在地图上显示每个对象,因此我必须使用 MapItemsControl 集合,而不是 MapElements 集合。
此集合绑定到对应 ViewModel 中的 ObservableCollection<PushpinViewModel> 对象 (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>
主视图模型:
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 Map Control - https://xamlmapcontrol.codeplex.com/ 进行了一些测试,结果令人惊讶。添加了 >1000 个元素的整体地图性能比原生 MapControl 差,但是,如果我调用 Add() x1000,然后是 Clear(),然后是 Add() x1000,PushpinViewModel 的终结器正在获得叫!内存被释放,应用程序不会崩溃。所以微软的MapControl肯定有问题...
【问题讨论】:
-
感谢您的回答。我正在调查这种可能性,并同意这确实可能是一个原因。我检查了您的链接,遗憾的是,发布的答案大多适用于 WPF 应用程序(我在 WinRT - 通用应用程序中)。我确实设法从流中加载了一张图片(作为一种异步方法,但它有效) - 不幸的是它没有帮助。内存消耗更大:(
-
我无法谈论您的具体问题,但 MapItemsControl 也有一些问题。我的设置与您所做的几乎完全相同——使用 MVVM 绑定到 ObservableCollection。如果我从地图导航到另一个视图,然后返回地图,并来回重复 3-5 次,我(通常)会收到“访问冲突”错误,我将其缩小到 MapItemsControl。我将其替换为获取项目源并为我在地图上绘制图钉的行为,如果您希望我发布源,请告诉我。
-
如果这不是问题@paul.abbott.wa.us,我将不胜感激。我联系了一些与微软相关的人,他们已经确认这是一个错误:social.msdn.microsoft.com/Forums/windowsapps/en-US/…,甚至提出了一个解决方法,但是,它不起作用。提前致谢!
标签: c# windows-phone-8 memory-leaks windows-phone-8.1 observablecollection