- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在根据 GC 性能分析一些简单的 C# 代码的结果。我使用 PerfView 并勾选了 GC Collect Only
来收集有意义的信息。
考虑 PerfView 的 GCStats 的以下相关输出,尤其是 GC#1106 和 #1108:
#1106 和#1108 都被列为 gen1 非并发 GC。两者都有 AllocLarge
的原因。
现在考虑关联的“谴责原因”表:
在a blogpost通过 .NET GC 的所有者 Maoni Stephens,我们知道一旦 GC 启动,它就可以对更高的 gen 进行操作,如下所示:
Now after the GC starts, we then decide what generation we would actually collect. It might stay as a gen0 GC, or get escalated to a gen1 or even a gen2 GC – this is something we decide as one of the very first things we do in a GC. And factors that would cause us to escalate to a high generation GC are what we called “condemned reasons” (so for a GC there’s only one trigger reason but can be multiple condemned reasons).
根据谴责原因表,事实证明,#1106 和 #1108 都将自己从 gen0 GC“提升”到 gen2 GC,因为它们都打破了 gen2 中的分配阈值。
但是怎么会:
1) #1106 和#1108 都以 gen0 GC 开始,最终“升级”到 gen2,但在 GCStats 中显示为 gen1 GC?请注意,这不是 PerfView 问题,因为详细的 ETW 事件在世代方面显示了相同的精确数据。
2) #1106 和#1108 都注册为 gen1 GC,但原因是 AllocLarge
? AllocLarge
指的是大超出了对象分配阈值,并且 LOH 只能作为 gen2 集合的一部分进行处理。
以上数据是在 Windows 10 x64 上运行的 .NET Framework 4.7.2 上捕获的。我假设 GC 决策背后的概念与其他相对较新版本的 .NET Framework 甚至 .NET Core 基本相同,因此这对此处提出的问题应该没有什么影响。
我也没有用实际代码来解决这个问题,因为导致 GC 以上述形式发生的原因不是由任何特殊指令触发的,而是由 GC 采取的内部决策触发的。
更新 1:我为最初的问题提供了更多数据。我还专门查看了围绕 GC#1106 和 #1108 引用的任何其他 Microsoft-Windows-DotNETRuntime*
ETW 事件,这些事件可以进一步阐明这两个问题。
更新 2:我已经更改了问题的名称,因为毕竟没有发生 gen2 GC。 CLR 仅针对 #1106 和 #1108 执行第 1 代 GC,因为第 2 代存活率列状态为 NaN
,这意味着没有运行第 2 代 GC。
查看 .NET Core CLR 源代码(从 .NET Framework 中可能发生的事情中获得灵感),执行实际 GC 工作的函数 gc_heap::gc1
在被谴责的生成早期读取信息(如下),如果这是一个非并发 GC(类似于我们的#1106 和#1108),它会继续针对相应代的标记阶段。 至于选择的被谴责的一代,在 gc_heap::generation_to_condemn
中,对超出的最高 gen 预算分配的检查是在检查低短暂段之前完成的,而后者不会t 覆盖该决定,而只是简单地选择之前被认为被谴责的任何一代与其自己的选择之间的最大值。尽管如此,我们知道最后一代的选择是正确的,因为在 GCStats 中被谴责的(最终)一代的数量是 2
。但为什么 GC 不采取行动这个决定?
最佳答案
感谢您向我们报告问题。我们已经研究这个问题一段时间了。 runtime support用于记录运行时实际原因已经合并,tooling support显示原因也基本完成,剩下的工作就是简单的打磨UI。
合并这些更改后,它将在下一版本的 .NET Core 和 PerfView 中可用。这应该使数据更准确地描述运行时发生的事情。
对于您的问题 1,#1106 和 #1108 的情况可能是avoid_unproductive
。我的更改会将此信息反射(reflect)到跟踪中。
对于你的问题2,当用户代码试图分配一个大对象而GC无法将其放入当前空闲列表时,它会触发GC,试图为该对象寻找空间。注意AllocLarge
是触发原因,触发原因和谴责原因是分开的。 trigger reasons描述了GC为什么会被触发,decended reasons描述了GC为什么选择某代去decend。
关于c# - 被谴责的一代不是垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59130015/
我是一名优秀的程序员,十分优秀!