关于内存运算符的C#内存分配

本文关键字:内存 分配 运算符 于内存 | 更新日期: 2023-09-27 18:26:50

我一直在运行基准测试,试图确定处理许多向量操作的最佳方式。我不担心计算效率,而是担心内存分配,这样我的程序就不会因为垃圾收集器清理堆中多余的向量而受到很大的影响。标准向量运算(+,*,normalize)是静态运算符重载,它接受两个向量并返回一个新向量。由于这些使用了新的运算符,我认为它会在堆中分配内存,并将赋值变量设置到该内存位置。这就得到了我最初的假设,即如果现有向量是赋值变量,则使用更新现有向量的方法。

这是使用矢量运算的标准代码。

var object1Pos = new Vector2(10, 5);
var object2Pos = new Vector2(-5, 3);
Vector2 object1Trajectory = (object2Pos - object1Pos).normalized;
object1Trajectory *= 8;
object1Pos += object1Trajectory;

这是使用方法更新矢量的代码。

var object1Pos = new Vector2(10, 5);
var object2Pos = new Vector2(-5, 3);
var object1Trajectory = new Vector2(object2Pos);
object1Trajectory.Add(object1Pos * -1);
object1Trajectory.Normalize();
object1Trajectory.Scale(8);
object1Pos.Add(object1Trajectory);

运行基准测试时,虽然方法代码的效率比运算符代码高35%(尽管提高幅度不大),但分配给堆和由垃圾收集器清理的数量是相同的。这对我来说没有意义,因为这表明要么操作符生成的向量是在堆栈上生成的,要么编译器正在进行一些优化,这样就不必在堆中分配新的内存。我想知道c#是如何分配内存的,编译器是怎么做的,这样就不会分配只在方法中使用的额外内存了?

关于内存运算符的C#内存分配

new运算符并不意味着C#中的堆分配。Vector2很可能是一个结构,所以只要它是一个局部变量,并且你没有做一些特殊的事情,比如在lambda中捕获它,即使你使用new,它也会在堆栈上分配。

有关类型和相关存储的更多信息,请参阅Eric Lippert关于该主题的精彩文章。