【发布时间】:2012-02-07 09:24:39
【问题描述】:
我运行以下代码
StringBuilder sb = new StringBuilder();
Stack stack = new Stack();
SynchronizationContext sc = new SynchronizationContext();
GC.Collect();
Console.WriteLine("GC. First Execution.");
stack = null;
GC.Collect();
Console.WriteLine("GC. Second Execution.");
GC.Collect();
Console.WriteLine("GC. Third Execution.");
在使用 SOS 调试此代码时,我看到在首次执行 GC 之后,地址如下:
!dso
...
0239b5f8 System.Threading.SynchronizationContext
0239b5a8 System.Collections.Stack
0239b560 System.Text.StringBuilder
...
Second Execution 后堆中没有“stack”对象,但其他地址为:
!dso
...
0239b5f8 System.Threading.SynchronizationContext
0239b560 System.Text.StringBuilder
...
所以“堆栈”对象已被收集,但 sc (SynchronizationContext) 对象并未重新定位到要压缩的内存中。我们的内存有缺口
!do 0239b5a8
Free Object
Size: 80(0x50) bytes
第三次执行后情况相同。
为什么会这样?为什么在这种情况下不执行“紧凑”操作?
谢谢。
【问题讨论】:
-
有趣。我猜想同步上下文包含一堆与单例模式相关的静态不可重定位字段。这可能是需要从另一个线程直接访问对象的情况。
-
谢谢。您是指“固定”对象吗?
-
我尝试对 SynchronizationContext 使用自定义 Foo 对象 - sutionations 是相同的。内存中的对象 Foo 不会被替换为压缩的男性堆。
-
更大的问题是为什么 all 对象没有被收集。不要测试你在 Debug 配置中编译的代码,你不会得到有代表性的结果。
-
谢谢各位。我在微软官方文档中找到了答案(抱歉没有链接,它是印刷文档)。将对象标记为未使用(待删除的候选对象)后,GC 执行计划阶段。 “计划:.NET 垃圾收集器为正在收集的每一代创建一个代预算,然后确定由于 GC 将在托管堆中发生的碎片量,以决定压缩是否有效。”但是我一直认为compaction总是由GC来完成的。我的知识存在差距,而不是 GC Heap )))