12

我一直在研究如何避免由INotifyCollectionChanged视图模型中对事件的强引用引起的内存泄漏。我正在使用 aListCollectionView来查看是否可以解决我的问题。我认为以下是泄漏内存,我做错了吗?

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(); 
}
4

6 回答 6

12

的文档ListCollectionView不是很好,但如果你注意到有一个方法DetachFromSourceCollection。此调用的备注提到取消订阅和允许垃圾收集。

    var stuff = new ObservableCollection<string>();
    while (true)
    {
        ListCollectionView result = new ListCollectionView(stuff);

        //Use this method to unsubscribe to events on the underlying collection and allow the CollectionView to be garbage collected.
        result.DetachFromSourceCollection();
        //When finished set to null
        result = null;
        GC.Collect();
    }
于 2015-11-24T16:09:39.893 回答
10

我最初将此作为评论发布,但我认为这是一个更好的答案,所以......

a) 如果您确定发现 .NET 框架存在问题,那么您可能做错了什么。这不是不可能,只是不太可能。b) 那 GC.Collect() 不会做你认为它会做的事情。

我认为您需要查看 GC.Collect() 的工作原理。


MSDN GC.Collect 方法

评论

使用此方法尝试回收所有不可访问的内存。

所有对象,无论它们在内存中存在多长时间,都会被考虑收集;但是,不会收集托管代码中引用的对象。使用此方法强制系统尝试回收最大数量的可用内存。


首先,你没有向我们展示你在哪里处理ListCollectionView(stuff). 你只是在分配新的和分配新的,但你从不处理旧的。所以,是的,它会像疯了一样泄漏。直到 GC 运行并尝试收集。

如果你用字符串列表做同样的事情,那么它很可能会做同样的事情。但是对于您所展示的内容,我希望它会泄漏。

于 2011-04-21T20:32:44.217 回答
2

当您调用 GC.Collect 时,您的变量结果仍在范围内,因此不会被收集,因为有一个指向数据的指针。无论如何,即使不是这样。就应用程序代码而言,垃圾收集的作用是不确定的。就像 drachenstern 说的,它只会尝试!它最终会成功,但你不能确定什么时候!

于 2011-04-21T20:45:25.803 回答
2

CollectionView 持有对源集合的 CollectionChanged 事件的引用 - 因此 GC 无法收集视图,直到源集合被释放和收集。

这从 CollectionView 的文档中也很清楚

    /// <summary>
    /// Detach from the source collection.  (I.e. stop listening to the collection's
    /// events, or anything else that makes the CollectionView ineligible for
    /// garbage collection.)
    /// </summary>
    public virtual void DetachFromSourceCollection()

该博客描述了您的问题并提出了两种可能的解决方案:
http ://www.eidias.com/blog/2014/2/24/wpf-collectionview-can-leak-memory ...

于 2015-11-27T15:11:36.790 回答
0

每次迭代result都被重新分配,这样就不会引用ListCollectionView上一次迭代中的 。GC.Collect但是,仅当 CLR 决定进行实际的垃圾回收时,才调用这些项目以回收它们的内存。如果您希望看到内存尽快被回收,请尝试GC.WaitForPendingFinalizers();在调用GC.Collect();.

于 2015-11-30T06:53:58.753 回答
0

最好的方法是使用 Scopes / Anonymous 函数。兰巴达对此很感激

var stuff = new ObservableCollection<string>();
ClosureDelegate closure = (x) => {
    ListCollectionView result = new ListCollectionView(x);
    //Use this method to unsubscribe to events on the underlying collection and allow the CollectionView to be garbage collected.
    result.DetachFromSourceCollection();
};

while (true)
{
    closure(stuff);
    GC.Collect(); 
}

使用此方法,您的抛出结果超出范围,因为它的方法已被删除,这将使用尽可能少的内存。

取自:https ://msdn.microsoft.com/en-gb/library/bb882516.aspx?f=255&MSPPError=-2147217396

于 2015-12-01T11:57:48.157 回答