如何识别不需要的、没有被垃圾收集的.net对象?

本文关键字:对象 net 何识别 识别 不需要 | 更新日期: 2023-09-27 18:16:24

我的(c# . net 4.0)应用程序运行了几天,根据从SQLite数据库获取的价格变化更新一个模拟帐户。

在任何特定日期,我所需要的只是当前状态的账户和最新价格。我希望垃圾收集器将内存使用保持在一个相当平稳的水平:我看到的是工作集和私有内存的稳定增长(如System.Diagnostics.GetCurrentProcess()所报告的),在GC.GetTotalMemory(true)中也是如此:在这种情况下,大约每天300K。不可避免地,整个系统在大约12个模拟年之后崩溃,此时内存使用增加了大约1GB。

内存使用或多或少呈线性增长(如果我在每天结束时强制执行GC.Collect(),则会更加平稳)。

我推断有些对象在某种程度上是不可垃圾收集的,即使我认为不再需要它们,并且预计它们会在正常的执行过程中被清理。

我应该试着识别我无意中造成这种情况的地方?

我已经下载并运行了CLRProfiler——它将花费周末最好的时间来消化文档,但是,不能保证它能提供帮助。

我正在查阅这道题中的参考资料。一般来说,我知道什么样的情况会导致问题,我更感兴趣的是看看是否有更快的方法来识别细节,而不必花费宝贵的时间在我的代码中勾选引用…

注意:问题似乎与事件无关,也没有涉及图形组件。

如何识别不需要的、没有被垃圾收集的.net对象?

您说您可以模拟导致应用程序崩溃的工作负载。为了快速找到您的泄漏,模拟工作负载,直到内存消耗变得显著(例如100 MB),将WinDbg或带有非托管调试的VS附加到您的进程并在即时窗口中运行:

.load sos
extension C:'WINDOWS'Microsoft.NET'Framework'v2.0.50727'sos.dll loaded
!dumpheap -stat
total 2885 objects
Statistics:
MT    Count    TotalSize Class Name
7a5eab18        1           12 System.Diagnostics.TraceOptions
(lots of unimportant stuff here)
79332b54      304         7296 System.Collections.ArrayList
79333274       56        11640 System.Collections.Hashtable+bucket[]
793042f4      345        50056 System.Object[]
79330b24     1041        99428 System.String
79332cc0       21    107109728 System.Int32[]

从这个(排序)输出,你可以告诉你有一个问题与int[]类型。类型:

!DumpHeap -type System.Int32[] (or whichever type you got)
Address       MT     Size
01381a1c 7931e9bc       40     
(cut)
075d1000 79332cc0 67108880     
03811000 79332cc0 40000016     
total 22 objects
Statistics:
MT    Count    TotalSize Class Name
7931e9bc        1           40 System.Int32[][]
79332cc0       21    107109728 System.Int32[]
Total 22 objects

现在你有了你的对象的地址。选择其中一个并运行

!GCRoot 075d1000

你会知道你漏水的原因。此外,您可能需要参考本教程。

是否使用事件?如果对象A订阅对象B上的事件,则B存储对A的引用。因此,A不能被垃圾收集,直到B可以被垃圾收集。如果A取消订阅B,则BA的引用将被删除。

我建议寻找一种启发式方法,即您可能从较短的实例中附加到较长存活实例中的事件的位置。如果您有一些实例在应用程序的生命周期中存在,并且您有侦听其上事件的寿命较短的类,那么未能解挂这些事件将导致您的寿命较短的对象被垃圾收集器跳过,因为寿命较长的对象挂在对它们的引用上,直到您将其分离。

编辑:为了它的价值,你可能想看看蚂蚁内存分析器。我不知道它与你现在看到的相比如何,但从试用来看,它的学习曲线并不差,所以你可能会花更少的时间来弄清楚它。