在 Pro.NET性能-优化您的C#应用的第96页中,讨论了GC eager root收集:
对于每个本地变量,JIT将嵌入一个表,其中包含变量作为根仍然相关的最早和最晚指针地址。 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
}
然后它说:
引述上面的讨论,将代码分成更小的方法并使用较少的本地变量不仅是一个好的设计措施或软件工程技术。对于.NET GC而言,这还可以提供性能优势,因为您有更少的本地根!这意味着编译方法时JIT需要处理的内容更少,占用根IP表格的空间更少,GC执行堆栈跟踪时需要处理的内容也更少。
我不明白如何通过将代码分成更小的方法来帮助。我已将代码分成以下部分:
static void Main(string[] args)
{
UseWidgetA();
//...additional code
UseWidgetB();
//...additional code
Foo(); //static method
}
static void UseWidgetA()
{
Widget a = new Widget();
a.Use();
}
static void UseWidgetB()
{
Widget b = new Widget();
b.Use();
}
}
本地跟踪器减少:
为什么本地跟踪器会减少呢? 每种方法中还是有一个本地跟踪器。
JIT编译时负担减轻:
这难道不会让情况变得更糟吗?因为需要2个额外的表来存储2个额外的方法。JIT编译器仍然需要记录变量在每个方法中相关的最早和最晚指针,在这方面它只是要处理更多的方法。
GC执行堆栈遍历时负担减轻:
有更多较小的方法如何能使GC在执行堆栈遍历时负担减轻呢?