在 Pro .NET性能的第96页-优化您的C#应用程序中,它讨论了GC急切的根集合:
对于每个局部变量,JIT会将表中的地址嵌入 最早和最新的指令指针,其中变量是 仍然是根源。然后,GC将使用这些表 执行它的堆栈遍历。
然后提供此示例:
posix/cpu,posix/mem
然后说:
以上讨论意味着将您的代码分解为更小的代码 方法和使用较少的局部变量不仅仅是一个好的设计 测量或软件工程技术。使用.NET GC,它可以 同时也提供性能优势,因为本地数量较少 根!这意味着在编译方法时,JIT的工作量减少了, 根IP表要占用的空间,并且GC的工作量减少 在执行堆栈遍历时。
我不明白将代码分解为较小的方法将有什么帮助。 我将代码分解为:
static void Main(string[] args)
{
Widget a = new Widget();
a.Use();
//...additional code
Widget b = new Widget();
b.Use();
//...additional code
Foo(); //static method
}
更少的本地根:
为什么本地根较少? 仍然有相同数量的本地根,每种方法中只有一个本地根。
编译方法时,JIT的工作量较少:
这肯定会使情况更糟,因为这2个额外方法需要2个额外表。 JIT仍需要记录最早和最新的指令指针,其中变量在每种方法中仍是相关的,但是它只会有更多的方法可以做到这一点。
执行GC堆栈遍历时,GC工作量减少:
采用更多较小的方法如何在堆栈遍历期间减少GC的工作量?
答案 0 :(得分:3)
我不在Sasha的脑海里,但让我为此付两分钱。
首先,我将其理解为通用规则-将方法拆分为较小的方法时,有可能不需要将某些部分进行JIT处理,因为某些子例程是有条件执行的。
其次,JITting确实生成了有关活动堆栈根的所谓的 GC信息。从理论上讲,越大的方法越大的 GC info 从理论上讲,在GC期间解释它的成本也应该更高,但是,可以通过将GC Info分成多个块来解决。但是,仅针对所谓的安全点存储有关堆栈根活动度的信息。方法有两种:
正如《运行时手册》所说:“ JIT选择是完全发射还是部分发射 基于启发式的可中断代码,以在代码质量, GC信息的大小以及GC暂停延迟。”
我认为,较小的方法可以帮助JIT做出更好的决策(基于其启发式方法),以使方法部分或完全可中断。