Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 谴责的生成不会被垃圾收集_C#_.net_.net Core_Garbage Collection_Clr - Fatal编程技术网

C# 谴责的生成不会被垃圾收集

C# 谴责的生成不会被垃圾收集,c#,.net,.net-core,garbage-collection,clr,C#,.net,.net Core,Garbage Collection,Clr,我在分析一些简单C代码的结果,从GC性能的角度来看。我已经使用PerfView和选中的GC Collect Only来收集有意义的信息 考虑PerfView的GCStats的以下相关输出,特别是GC#1106和#1108: #1106和#1108均列为第1代非并发地面军事系统。两者都有AllocLarge的原因 现在考虑相关的谴责原因表: 在.NET GC的所有者Maoni Stephens的文章中,我们知道一旦GC启动,它就可以针对更高的一代,如下所示: 现在,在GC启动之后,我们再决定我

我在分析一些简单C代码的结果,从GC性能的角度来看。我已经使用PerfView和选中的GC Collect Only来收集有意义的信息

考虑PerfView的GCStats的以下相关输出,特别是GC#1106和#1108:

#1106和#1108均列为第1代非并发地面军事系统。两者都有
AllocLarge
的原因

现在考虑相关的谴责原因表:

在.NET GC的所有者Maoni Stephens的文章中,我们知道一旦GC启动,它就可以针对更高的一代,如下所示:

现在,在GC启动之后,我们再决定我们将使用哪一代 实际收集。它可能保持为gen0 GC,或者升级为 gen1甚至gen2 GC–这是我们确定的 我们在GC中首先要做的事情。以及导致我们 升级到高代GC是我们所谓的“谴责” 原因”(因此对于GC,只有一个触发原因,但可以是 多种原因)

根据谴责原因表,结果表明#1106和#1108都“提升”了自己从第0代GCs到第2代GCs的等级,因为这两个等级都打破了第2代GCs的分配阈值

但是,为什么:

1) 1106和1108都以第0代地面军事开始,最终“升级”到第2代,但在GCStats中显示为第1代地面军事?请注意,这不是PerfView的问题,因为详细的ETW事件在世代方面显示了相同的精确数据

2) 1106和1108都注册为gen1 GCs,但原因是
AllocLarge
AllocLarge
指超出了大对象分配阈值,LOH只能作为gen2集合的一部分进行处理

上面的数据是在Windows 10 x64上运行的.NET Framework 4.7.2上捕获的。我假设GC决策背后的概念对于其他相对较新版本的.NET Framework,甚至是.NET Core来说基本相同,所以这与这里的问题没有什么区别

我也没有用实际的代码来回答这个问题,因为导致GCs以上述形式出现的原因并不是由任何特殊指令触发的,而是由GC做出的内部决定触发的

更新1:我已经为最初的问题提供了更多数据。我还特别查看了GCs 1106和1108中引用的任何其他
Microsoft Windows DotNETRuntime*
ETW事件,但找不到任何可以对这两个问题提供更多信息的事件

更新2:我更改了问题的名称,因为根本没有发生gen2 GCs。CLR仅对#1106和#1108执行第1代GC,因为第2代生存率列表示
NaN
,这意味着没有运行第2代GC

查看.NET核心CLR源代码(以了解在.NET Framework中可能发生的情况),执行实际GC工作的函数
GC#u heap::gc1
会在早期读取谴责的生成信息(如下),前提是这是一个非并发GC(类似于我们的#1106和#1108)它针对相应的生成进行标记阶段。
对于所选的谴责生成,在
gc_heap::generation_to_dural
中,检查超出的最高生成预算分配在检查低瞬时段之前完成,后者不会覆盖决策,但只是在被认为是有罪的那一代和它自己的选择之间选择最大值。尽管如此,我们知道最终一代的选择是正确的,因为在GCStats中被定罪(最终)一代的数量是
2
。但是为什么GC没有按照这个决定行事呢?

我已经联系到了Maoni,她非常友好地指出,在这个问题中观察到的行为是由于一个调整逻辑,它阻止了连续的gen2 GC发生,而不是退回到gen1 GC


目前正在进行工作,以便使用ETW(至少使用.NET Core)正确记录gen2-GCs的备份行为,Maoni为此专门发布了一个问题。

感谢您向我们报告此问题。我们在这个问题上已经做了一段时间了。在运行时记录实际原因的工作已经合并,显示原因的工作也基本完成,剩下的工作只是润色UI

合并这些更改后,它将在下一版本的.NET Core和PerfView中可用。这将使数据更准确地描述运行时发生的情况

对于您的问题1,#1106和#1108的情况可能是
avoid\u非生产性的
。我的更改会将此信息反映到跟踪中


对于问题2,当用户代码试图分配一个大对象,而GC无法将其放入当前可用列表时,它将触发一个GC,试图为该对象寻找空间。请注意,
allocclarge
是一个触发原因,触发原因与谴责原因分开。触发原因描述了GC被触发的原因,而谴责原因描述了GC选择某一代进行谴责的原因。

谢谢,Andrew。我已经看到关于PerfView请求的讨论仍在进行中。感觉很自然的是:(a)我在GC事件表中看到1106,带有“AllocLarge”,但Gen为1N。(b) 我知道发生了一些意想不到的事情,所以我看了看谴责理由表。(c) 我在新的“Avoid_unproductive”列中找到了相应的“1”。(d) 我看了看“最后一代”,看到了“1”,这让我发现“避免低效”赢了,尽管“超出了一代预算”是“2”。理想情况下,让“赢家”用粗体字谴责理由将是一件好事。