C#中“新”的性能成本?

在C#中,使用new关键字的性能成本是多少? 我特别提到了与游戏开发有关的问题,我知道在C ++中,每个更新周期都是新手,这是一个明确的禁忌。 这同样适用于C#吗? 我正在使用XNA并开发移动设备。 只是真的问一个优化问题。

new成本分为三个部分:

  • 分配内存(如果是值类型,则可能不需要)
  • 运行构造函数(取决于你正在做什么)
  • 垃圾收集成本(同样,如果它是值类型,则可能不适用,具体取决于上下文)

在没有在主代码中创建任何新对象的情况下,很难习惯性地使用C#…虽然我敢说尽可能重用对象是可行的。 尝试抓住一些真实的设备,看看你的游戏表现如何。

我当然同意在编程中通常要避免像这样的微优化,但它更适合游戏循环而不是其他地方 – 因为很明显游戏对即使是小的暂停也非常敏感。 但是,判断使用更多对象的成本可能非常困难,因为它会因GC成本而随着时间的推移而分散。

分配器和垃圾收集器在.NET中相当不错,虽然它可能在设备上更简单(我认为是Windows Phone 7)? 特别是,我不确定Compact Framework CLR(WP7使用的是否具有)是否具有分代GC。

C#中的分配实际上比在C ++中更快。 它只涉及增加堆指针并返回该指针。 通常,对象在C#中比在C ++中更频繁地被newed ,因为在字符串之类的东西中有更多的不变性。

正如其他人所指出的那样,真正的野兽是垃圾收集器,这有点棘手。 尽管如此,即使GCing在大多数情况下也快于C ++中的delete速度 – 只是你无法预测它何时会发生。

.NET团队中的人物Rico Mariani的一些提示: http : //msdn.microsoft.com/en-us/library/ms973837.aspx

它有点陈旧,GC上有一些改进,但大部分信息仍然相关。

我应该补充一点,虽然XNA / Compact Framework垃圾收集器比x86版本稍慢,以便在内存性能上牺牲CPU,所以你应该注意这一点。

编辑

我忘了提及,这很重要: 值类型 ,包括结构,也使用new语法,但是它们是在堆栈而不是堆上创建的,所以除非你打包它们,否则没有GC成本。

新运营商本身的成本可以忽略不计。 可能需要花费的成本是在自定义构造函数中进行的处理。 因此,如果你在这个构造函数中有很多事情发生,那可能是个问题。

您应始终以“最简单”的方式编码, 然后测量瓶颈( 如果存在)。

无论如何,我永远不会用C#编写游戏。

编辑

因为它引起了怨恨,我的意思是如果 C ++是一个可用的选项,我永远不会在C#中编码。 这是我的想法,因为OP也标记了C ++。

new本身的成本很可能并不重要,但是当在堆上分配新对象(当创建引用类型的实例时)可能触发垃圾收集时,副作用在游戏中可能是重要的。 如果您担心GC,可以使用值类型或重用对象。

此外,正如Darin正确指出的那样,构造函数可能会做很多工作。

在C#中,内存由垃圾收集器进行碎片整理,因此查找和分配内存是一种非常快速的操作。 但是,GC执行的偶尔碎片整理可能会大大减慢

在c#中几乎没有与新运算符相关的成本,但是当您在引用类型上使用new时,将在那里进行堆分配,这由GC维护。 如果内存是连续的,那么分配内存只是一个指针移动但是如果找到两个分配之间的GAP而不是GC将查询可用内存的自由列表(链接列表)以找到所需的对象,这将需要一些时间查询o(n旅行时间。

请参阅Eric Lippert的post

当您在c#中编写新内容时,CLR会将内存分配给托管堆上的对象。

请查看以下链接了解更多信息:

http://msdn.microsoft.com/en-us/library/ee787088(v=vs.100).aspx

由于垃圾收集在C#中是自动的(仅在测试期间人们使用GC.Collect手动触发它时),c#上的游戏设计是个坏主意。

你应该寻找C ++,因为你有析构函数。

 ~ClassName() { //kill my object and reclaim memory. } 

我的测量显示,参考类型的“新”有时可能需要2.2秒,有时可能会快几个滴答。 底线是.net GC中没有实时保证,性能随机变化很大。 所以我建议实时设计,例如游戏,不要在代码的实时部分中引用“新”引用类型(例如更新循环),因为没有实时保证。

当然,很多人会争辩说,“新”需要花费2.2秒的时间,如果只发生几个小时一次,那就更重要了。 那么这必须是设计师的判断。 但是为了学术论证,GC不是实时的,因此不要在实时代码中称为“新”。