【问题标题】:Details of write barriers in the .Net Garbage Collector.Net 垃圾收集器中的写入屏障的详细信息
【发布时间】:2017-12-15 08:14:55
【问题描述】:

我在大对象堆的第 2 代中有一个大的 T[]T 是一个引用类型。我做了以下作业:

T[0] = new T(..);

  • 对于 GC 的下一个 Gen0/Gen1 标记阶段,哪些对象被标记为脏?整个数组实例,还是只是T 的新实例?下一个 Gen0/Gen1 GC 标记阶段是否必须遍历数组的每一项? (这似乎没有必要,而且效率很低。)
  • 数组在这方面有什么特殊之处吗?如果集合是例如,它会改变答案吗? SortedList<K, T> 我添加了一个新的最大项目?

我已经阅读了许多问题和文章,包括以下内容,但我仍然认为我没有找到明确的答案。 我知道整个内存范围都被标记为脏,而不是单个对象,但是新的数组条目或数组本身是这个的基础吗?

card table and write barriers in .net GC

Garbage Collector Basics and Performance Hints

【问题讨论】:

  • 这是一个很好的问题。我不知道写屏障适用于范围。如果是这种情况,那么数组的一部分无效(因为它是连续的内存)似乎是合乎逻辑的,但实际上没有理由让整个数组无效。假设 msdn 文章中提到的 128 字节范围,并且在 x64 架构(8 字节指针大小)上,这意味着 16 项无效。我认为它不会对性能产生重大影响。但是文章似乎使用了示例值,我想知道真正的值是什么
  • 查看.net core GC(raw.githubusercontent.com/dotnet/coreclr/master/src/gc/gc.cpp)的代码,似乎比文章中暗示的要复杂得多。值得注意的是,似乎有一个“卡片包”机制,引用“跟踪卡片词组”。我试图弄清楚卡包是文章中提到的“范围”,还是它上面的其他机制
  • @KevinGosse,谢谢。我假设 GC 以一种智能的方式管理代际引用,并且在 gen2 SortedList 末尾附近的插入不会为 GC 创建大量工作。

标签: c# .net arrays garbage-collection


【解决方案1】:

在 GC 的下一个 Gen0/Gen1 标记阶段,哪些对象被标记为脏对象?整个数组实例,还是只是 T 的新实例?

包含数组开头的 128B 块将被标记为脏。新创建的实例 (new T()) 将是一个新对象,因此它将首先通过没有卡表的 Gen 0 集合进行检查。

为简单起见,假设数组的开头对齐在 128B 边界上,这意味着第一个 128B 将无效,因此假设 T 是引用类型并且您在 64 位系统上,即下一次收集时要检查的前 16 个项目。

下一个 Gen0/Gen1 GC 标记阶段是否必须遍历数组的每个项目? (这似乎没有必要,而且效率很低。)

只有这 16 到 32 项,具体取决于此架构中的指针大小。

数组在这方面有什么特别之处吗?如果集合是例如,它会改变答案吗?一个 SortedList,我添加了一个新的最大项目?

数组并不特殊。 SortedList<K,T> 在内部维护两个数组,因此在一般情况下,更多的块最终会变脏。

【讨论】:

    【解决方案2】:

    很确定它的跟踪数组槽,而不是持有对数组对象本身的引用的根。 顺便说一句,如果特定卡设置为脏,它必须扫描 4k 内存。我现在使用 Windows 自己的机制在某处读取它,如果感兴趣的内存范围被写入,您可以收到通知。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-04
      相关资源
      最近更新 更多