2016-07-05 15 views
0

我有一个WPF应用程序,允许用户打开,关闭并重新打开任意数量的子窗口。如果一个对象的终结器已被调用,我可以100%确定它是/将在以后从内存中删除吗?

使用VS2015的集成内存分析器,我发现,某些类型的子窗口中,让我们叫它ProblematicChildWindow,始终保持在内存中已被关闭之后,所以它的情况下频繁密切的情况下加起来,然后重新打开动作。不幸的是我不能在最小程度的应用程序中重现问题(一切正常)。

我知道WPF的常见内存泄漏情况,我得出的结论是,剖析器必须是错误的。所以我下面的代码添加到有问题的类:

~ProblematicChildWindow() 
{ 
    using (StreamWriter sw = File.CreateText("d:\\garbagecollection.txt")) 
    { 
     sw.WriteLine(DateTime.Now.ToShortTimeString() + " garbage collected."); 
    } 
} 

现在奇怪的是:

打开和关闭的ProblematicChildWindow一个实例,并迫使垃圾收集后,我发现一个新的文件“ garbagecollection.txt“在我的D:\文件夹中,但是

VS2015的内存分析器告诉我在内存中仍存在ProblemsmaticChildWindow的实例!

我的问题:由于实例显然已经被垃圾收集(因为终结器已被调用),我可以确定占用的内存会被释放吗?

VS2015的内存分析器似乎在这种情况下有一个错误。

更新: .NET内存分析器告诉我关闭后内存中没有任何实例。但VS2015确实(只是再次检查)。

+0

如果强制垃圾收集*两次*会发生什么?具体来说,'GC.Collect(); GC.WaitForPendingFinalizers();所以GC.Collect();'。 –

+4

实际上,当终结者被调用时,你还没有被垃圾收集。毕竟,如果是这样,你的对象的终结器怎么会被调用呢?如果它仍然符合条件,它将被标记为收集,但是,终结器实际上最终可能会结束讨论该对象。 – willaien

+1

你可能想阅读Eric Lippert的博客文章[当你知道的一切都是错误的](https://ericlippert.com/2015/05/18/when-everything-you-know-is-wrong-part-one/) – juharr

回答

0

没有,这就是为什么我们有一个像GC.WaitForPendingFinalizers的方法:

当垃圾收集器找到可以回收的对象,它 检查每个对象以确定对象的终结 要求。如果一个对象实现了一个终结器,并且没有通过调用SuppressFinalize来禁用最终化,那么该对象将被放置在一个标记为可以完成的对象列表中。垃圾 收集器调用此列表中的对象的Finalize方法, 从列表中删除条目。此方法阻止,直到所有的 终结器运行完成。

运行终结器的线程未指定,因此没有保证此方法将终止。但是,当WaitForPendingFinalizers 方法正在进行时,此线程可能由另一个线程中断 。例如,如果 线程仍处于挂起状态,您可以启动另一个线程,等待一段时间,然后中断此线程。

0

终结器被垃圾回收器调用,当它将对象识别为未使用的对象时。但不保证,对象将被收集。如果对象引用了未被关闭的非托管资源,则可能会发生这种情况。

检查该类中使用的资源。其中一些必须仍然开放。

0

否。确定对象后仍然可以对非托管资源进行一些引用。检查内部泄漏。

相关问题