我写了一个小型的控制台应用实验:
static void Main()
{
int GetTotalCollections()
{
var total = 0;
for (var generation = 0; generation <= GC.MaxGeneration; generation++)
total += GC.CollectionCount(generation);
return total;
}
CreateGarbage();
WriteLine("Number of collections occurred: {0}", GetTotalCollections());
}
static void CreateGarbage()
{
WriteLine(new object().GetHashCode());
WriteLine(new object().GetHashCode());
WriteLine(new object().GetHashCode());
ReadKey();
}
当我在没有附加调试器的情况下以Release
模式运行它时,我会收集所有代的0
个集合。
由于看起来很奇怪,我将WinDbg
附加到流程中,而!dumpheap -live
并未显示对象,而!dumpheap
则表示对象。遗憾的是-live
不是 SOS 官方文档的一部分,但我假设它只显示未收集的对象。
GC
是否正在收集并且没有报告(在这种情况下应该如此)或者我误解了!dumpheap -live
输出? (可能只显示带有GC root
的对象?)
如果我分配更多对象以确保我触发一个集合(或调用 GC.Collect
)我会收集计数增加,但在WinDbg中仍然是相同的输出:
static void GetValue()
{
for (var i = 0; i < 1000000; i++)
new object();
ReadKey();
}
编辑:最后一句话是疏忽(导致混淆),如果我强制收集,!dumpheap -stat
不再按预期显示对象(我只是忘了从{{1)运行应用程序在按一个键强制收集之前。)
WinDbg
显示未收集的实时和死亡对象,!dumpheap -stat
仅显示@Thomas回答时!dumpheap -stat -live
的对象。收集后,它们会从所有命令的输出中消失。
答案 0 :(得分:3)
不,GC不收集而不报告,它还没有运行任何收藏。仅仅因为您已经创建了一些符合条件的集合的对象并不意味着任何集合实际发生了,只有当集合发生时对象将被它清理干净。根据大量的启发式方法,GC实际上会在它认为需要的时候运行。
答案 1 :(得分:3)
不幸的是,-live不是SOS官方文档的一部分
当我输入!help dumpheap
时,它会说:
-live Only print live objects
-dead Only print dead objects (objects which will be collected in the
next full GC)
活动对象是garbage collection root引用的对象,死对象是不再具有此类引用的对象,只要.NET认为是时候这样做就可以进行垃圾收集。
在活动对象和死对象上运行!gcroot
时,您应该能够找到差异。活动对象应连接到根(固定句柄,线程,静态变量,可释放队列......),但死对象不是。
死对象的示例:
0:007> !gcroot -all 029e3be4
Found 0 roots.
活动对象的示例:
0:007> !gcroot -all 029e406c
HandleTable:
00b913f0 (pinned handle)
-> 039e24d0 System.Object[]
-> 029e406c System.String
Found 1 roots.