ListCollectionView 是否泄漏内存?
我一直在研究如何避免由于视图模型中对 INotifyCollectionChanged 事件的强引用而导致的内存泄漏。我正在尝试使用 ListCollectionView
来看看这是否可以为我解决这个问题。我认为以下内容正在泄漏内存,我做错了什么吗?
var stuff = new ObservableCollection<string>();
while (true)
{
var result = new ListCollectionView(stuff);
// Just to keep make sure that the memory I'm seeing
// isn't waiting to be GC'd
GC.Collect();
}
I've been investigating how to avoid memory leaks caused by strong references to the INotifyCollectionChanged
event from a view model. I was playing around with using a ListCollectionView
to see if that would deal with it for me. I think that the following is leaking memory, am I doing something wrong?
var stuff = new ObservableCollection<string>();
while (true)
{
var result = new ListCollectionView(stuff);
// Just to keep make sure that the memory I'm seeing
// isn't waiting to be GC'd
GC.Collect();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
ListCollectionView
的文档不是很好,但如果您注意到有一个方法DetachFromSourceCollection
。这次电话会议的备注提到了取消订阅和允许垃圾收集。The documentation for
ListCollectionView
is not great but if you noticed there is a methodDetachFromSourceCollection
. The remarks for this call mention unsubscribing and allowing garbage collection.我最初将其作为评论发布,但我认为它提供了更好的答案,所以...
a) 如果您确定发现了 .NET 框架的问题,那么您可能做错了什么。这并非不可能,只是不太可能。
b) GC.Collect() 不会做你想象的事情。
我认为您需要回顾一下 GC.Collect() 的工作原理。
MSDN GC.Collect 方法
备注
使用此方法尝试回收所有内存那是无法到达的。
所有对象,无论它们在内存中存在多长时间,都将被考虑收集;但是,不会收集托管代码中引用的对象。使用此方法强制系统尝试回收最大可用内存量。
首先,您不会向我们展示您在何处处理
ListCollectionView(stuff)
的内存。你只是分配新的并分配新的,但你永远不会处理掉旧的。所以是的,它会疯狂地泄漏。直到 GC 运行并尝试收集。如果您使用字符串列表执行此处演示的相同操作,它很可能会执行相同的操作。但就你所展示的内容而言,我预计它会泄露。
I initially posted this as a comment, but I think it makes a better answer, so ...
a) if you're sure you've found a problem with the .NET framework, you're probably doing something wrong. It's not impossible, it's just not likely.
b) that GC.Collect() isn't going to do what you're thinking it will.
I think you need to review how GC.Collect() works.
MSDN GC.Collect Method
Remarks
Use this method to try to reclaim all memory that is inaccessible.
All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory.
For starters, you don't show us where you're disposing of that memory that the
ListCollectionView(stuff)
. You're just allocating new and allocating new, but you never dispose of the old. So yeah, it's going to leak like crazy. Until the GC runs and tries to collect.If you do the same thing you demonstrate here with a list of strings it will most likely do the same thing. But for what you've shown, I expect it to leak.
当您调用 GC.Collect 时,变量结果仍在范围内,因此不会收集它,因为有一个指向数据的指针。无论如何,即使事实并非如此。就应用程序代码而言,垃圾收集的作用是不确定的。就像drachenstern说的,它只会尝试!它最终会成功,但你不能确定什么时候!
when you call GC.Collect, you variable result is still in scope so it won't be collected since there is one pointer to the data. anyway even if it wasn't the case. what garbage collection does is non deterministic as far as application code is concerned. like drachenstern said it will only try! and it will succeed eventually but you can't be sure when!
CollectionView 持有对源集合的 CollectionChanged 事件的引用 - 因此 GC 无法收集视图,直到源集合被处置并收集。
CollectionView 的文档也清楚地表明了这一点。
该博客描述了您的问题并提出了两种可能的解决方案:
http://www.eidias.com/blog /2014/2/24/wpf-collectionview-can-leak-内存 ...
The CollectionView holds a reference to the source collection’s CollectionChanged event - hence GC can not collect the view until the source collection is disposed off and collected.
This is also clear from the documentation of CollectionView
This blog describes your issue and suggest two possible solutions:
http://www.eidias.com/blog/2014/2/24/wpf-collectionview-can-leak-memory ...
每次迭代都会重新分配
结果
,以便不会引用上一次迭代中的ListCollectionView
。但是,调用 GC.Collect 只会在 CLR 决定执行实际垃圾回收时安排这些项目回收其内存。如果您希望更快地回收内存,请尝试在调用GC.Collect();
之后立即添加GC.WaitForPendingFinalizers();
。With each iteration
result
is being reassigned so that there won't be a reference to theListCollectionView
from the previous iteration. But callingGC.Collect
only schedules those items to have their memory reclaimed when the CLR decides to do the actual garbage collection. If you would like to see the memory getting reclaimed sooner, try addingGC.WaitForPendingFinalizers();
immediately after your call toGC.Collect();
.最好的方法是使用作用域/匿名函数。 Lambada 很高兴
使用此方法将结果抛出范围之外,因为它的方法已被删除,这将使用尽可能少的内存。
摘自:https://msdn.microsoft.com/en-gb/library/bb882516.aspx?f=255&MSPPError=-2147217396
The best way to do this is to use Scopes / Anonymous functions. Lambada is grate for that
Using this method your throwing result out of scope as its method has been removed and this would use as little memory as possible.
Taken from: https://msdn.microsoft.com/en-gb/library/bb882516.aspx?f=255&MSPPError=-2147217396