C#GC没有收集没有root的对象

时间:2014-10-03 19:01:43

标签: c# memory-leaks garbage-collection

我从文件(例如,1.00E + 7个对象)中读取一些数据到对象列表中。然后我将它们传递给另一个将在每个类上进行转换然后序列化到磁盘的类。在这个过程中,我有相当大的内存泄漏。

使用!dumpheap -stat我发现我的几个类占用了大量内存,如下所示:

MT         count     TotalSize ClassName
00185fd0   196180      7847200 Di3BMain.PeakDataClass
0070d25c   392429      9418296 System.Collections.Generic.List`1[[DI3.Lambda`2[[System.Int32, mscorlib],[Di3BMain.PeakDataClass, Di3Main]], Di3]]
00707038   392360     10986080 DI3.B`2[[System.Int32, mscorlib],[Di3BMain.PeakDataClass, Di3Main]]
00930a0c    15453     12821476 CSharpTest.Net.Collections.BPlusTree`2+Element[[System.Int32, mscorlib],[DI3.B`2[[System.Int32, mscorlib],[Di3BMain.PeakDataClass, Di3Main]], Di3]][]
7282fe8c   393241     13307220 System.Object[]
72843a70      250    641899364 System.Int32[]

考虑到数量和大小,它清楚地表明创建了同一对象的许多实例,正如我所期望的那样(一个输入对象的一个​​output-serializ对象)。但是我应该按照我期望的代码收集每个新对象,其格式非常简单如下:

serializer.Add(new ConvertedObject( ... ){ ... });

为了理解泄漏,我试图检查一些最大条目的根源;例如MT: 00707038使用!gcroot -all 00707038;但它给我的是Found 0 roots.

鉴于在所有这些统计数据之前,我使用以下代码强制GC,我想知道为什么GC没有收集任何没有根的大对象?甚至推完它之后!

GC.Collect();
GC.SuppressFinalize(this);
GC.WaitForPendingFinalizers();

1 个答案:

答案 0 :(得分:4)

  1. !gcroot -all 0070703800707038是方法表的地址。要查找对象是否有根,您需要选择该类的实例,即使用对象地址,不是方法表地址。使用dumpheap -mt(无-stat)与MT地址将转储给定类的对象列表(在您的情况下,列表可能很长..因此您可以考虑限制输出的方法,或者几个人被甩在屏幕上后休息。)
  2. 获得对象地址后,请在该地址上运行gcroot

    1. 另一方面,请注意,因为对象没有root,并不意味着,GC没有收集它...取决于对象所在的生成,gc最后运行给定代,以及何时你接受了转储,未转根的对象在转储中显示可能是正常的。
    2. GC可能不会收集每一代和每个对象,除非它认为系统处于内存压力之下。