C#中的内存布局优化
Memory layout optimization in C#
免责声明:下面的措辞可能存在一些误解,如果我误解了我的代码是在 C# 中处理的,从我编写它到它看起来像零和一的那一刻,请纠正我
问题如下(已链接):
在 C# 中,无论我是否使用优化技术,我的数据结构 and/or 我的数据操作实现是否有任何方法会对性能产生影响?
编译器在输出IL时是做什么的,靠谱吗?
意思是:如果我让我的数据成为 SOA,它会是 IL 中的 SOA 吗?总是?
当 JIT 读取 IL 时,我的数据结构会发生什么变化?它改变了吗?它是否自动优化以适应我的处理器?
我知道这个演讲是针对本机代码的,讨论处理器布局与本机代码中的数据布局的具体细节。
我也知道 C# 编译器和 JIT 编译器会针对这些问题为我优化内容。
基本上我想知道这些优化是否会对我的性能产生影响:
- SOA 而不是 AOS
- 向量访问模式(在内存中连续访问)
- 等...你的名字...
我从事游戏开发工作,性能至关重要,我们处理大量数据,我们需要每秒至少处理 24 次,我不能让 GC 处理 300 毫秒或内存 accessed/allocated 当我试图检测 3000 个不同对象之间的碰撞时到处都是
关于我阅读但没有真正回答问题的内容的参考:
Excellent Eric Lippert article about structs and values types in C#(如果您认为在 C# 中值类型总是在堆栈上,请阅读它)
Excellent video about PerfView to track your GC behaviour and it's impact on your perfs
That SO question about Best practices to optimize memory in C#(更重要的是它的答案)
但是这些并没有回答与处理器和数据布局实施相关的性能成本。
在 Hans 回答之后更进一步:
当你说:"You can pursue SOA but that doesn't help. Yes, your program will slow down because of all that structure copying and does so in a deterministic way. But it doesn't stop the rain. You get the worst of both, a slow program and the exact same pauses."
这并不意味着我的程序没有从 SOA 中受益,它会(可能)更快,因为它有助于处理我的数据。只是对GC本身没有影响。
另一件事是,如果我不对我的数据布局进行 SOA 或其他改进,编译器就不会为我改进它,对吗?我不能依靠编译器来处理那种事情吗?
担心GC就像担心今天会不会下雨。迟早要下雨,你无能为力。 需要,否则就无法让草坪看起来很绿。你永远不想做的是故意阻止下雨。因为如果你这样做,它会倾盆大雨,淹没那片漂亮的草坪。持续的毛毛雨是你想要的。最好在晚上不看的时候。
.NET GC 强烈支持这一点。只有小型 gen #0 和 #1 集合会暂停您的程序。当您的代码继续执行时,昂贵的 gen#2 收集在后台发生。最坏情况下的暂停徘徊在接近一百微秒的某个地方。这与 其他 程序在现代 OS 上暂停的原因几乎没有区别。就像您的游戏循环暂时暂停一样,因为另一个更高优先级的内核线程需要 运行。只是一场毛毛雨,肉眼看不到。
您可以追求 SOA,但这无济于事。是的,你的程序会因为所有的结构复制而变慢,并且是以一种确定的方式进行的。但这并不能阻止雨。你得到了两者中最糟糕的,一个缓慢的程序 和 完全相同的暂停。
不用担心下雨,只要确保它在正确的时间下。要利用后台 GC,您需要构建数据,使其存在时间非常短,因此它很容易随着 gen #0/1 收集而消失。或者活了很长时间,所以它在第 2 代找到了一个舒适的家,并在那里呆了一段时间。这通常是程序中非常常见的模式,尤其是在游戏中。你不太可能需要做任何事情。
免责声明:下面的措辞可能存在一些误解,如果我误解了我的代码是在 C# 中处理的,从我编写它到它看起来像零和一的那一刻,请纠正我
问题如下(已链接):
在 C# 中,无论我是否使用优化技术,我的数据结构 and/or 我的数据操作实现是否有任何方法会对性能产生影响?
编译器在输出IL时是做什么的,靠谱吗? 意思是:如果我让我的数据成为 SOA,它会是 IL 中的 SOA 吗?总是?
当 JIT 读取 IL 时,我的数据结构会发生什么变化?它改变了吗?它是否自动优化以适应我的处理器?
我知道这个演讲是针对本机代码的,讨论处理器布局与本机代码中的数据布局的具体细节。
我也知道 C# 编译器和 JIT 编译器会针对这些问题为我优化内容。
基本上我想知道这些优化是否会对我的性能产生影响:
- SOA 而不是 AOS
- 向量访问模式(在内存中连续访问)
- 等...你的名字...
我从事游戏开发工作,性能至关重要,我们处理大量数据,我们需要每秒至少处理 24 次,我不能让 GC 处理 300 毫秒或内存 accessed/allocated 当我试图检测 3000 个不同对象之间的碰撞时到处都是
关于我阅读但没有真正回答问题的内容的参考:
Excellent Eric Lippert article about structs and values types in C#(如果您认为在 C# 中值类型总是在堆栈上,请阅读它)
Excellent video about PerfView to track your GC behaviour and it's impact on your perfs
That SO question about Best practices to optimize memory in C#(更重要的是它的答案)
但是这些并没有回答与处理器和数据布局实施相关的性能成本。
在 Hans 回答之后更进一步:
当你说:"You can pursue SOA but that doesn't help. Yes, your program will slow down because of all that structure copying and does so in a deterministic way. But it doesn't stop the rain. You get the worst of both, a slow program and the exact same pauses."
这并不意味着我的程序没有从 SOA 中受益,它会(可能)更快,因为它有助于处理我的数据。只是对GC本身没有影响。
另一件事是,如果我不对我的数据布局进行 SOA 或其他改进,编译器就不会为我改进它,对吗?我不能依靠编译器来处理那种事情吗?
担心GC就像担心今天会不会下雨。迟早要下雨,你无能为力。 需要,否则就无法让草坪看起来很绿。你永远不想做的是故意阻止下雨。因为如果你这样做,它会倾盆大雨,淹没那片漂亮的草坪。持续的毛毛雨是你想要的。最好在晚上不看的时候。
.NET GC 强烈支持这一点。只有小型 gen #0 和 #1 集合会暂停您的程序。当您的代码继续执行时,昂贵的 gen#2 收集在后台发生。最坏情况下的暂停徘徊在接近一百微秒的某个地方。这与 其他 程序在现代 OS 上暂停的原因几乎没有区别。就像您的游戏循环暂时暂停一样,因为另一个更高优先级的内核线程需要 运行。只是一场毛毛雨,肉眼看不到。
您可以追求 SOA,但这无济于事。是的,你的程序会因为所有的结构复制而变慢,并且是以一种确定的方式进行的。但这并不能阻止雨。你得到了两者中最糟糕的,一个缓慢的程序 和 完全相同的暂停。
不用担心下雨,只要确保它在正确的时间下。要利用后台 GC,您需要构建数据,使其存在时间非常短,因此它很容易随着 gen #0/1 收集而消失。或者活了很长时间,所以它在第 2 代找到了一个舒适的家,并在那里呆了一段时间。这通常是程序中非常常见的模式,尤其是在游戏中。你不太可能需要做任何事情。