【问题标题】:Performance cost of 'new' in C#?C#中“新”的性能成本?
【发布时间】:2011-05-14 07:33:41
【问题描述】:

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

【问题讨论】:

  • 你认为你的问题真的需要 C++ 标签吗?您的问题与 C++ 无关,可以在没有提及它的句子的情况下提出。 (换句话说,没有 C++ 经验的人可以回答这个问题。)
  • 我希望有 C++ 经验的人回答这个问题,因为我有 C++ 程序员的背景,想了解它与 C# 的细微差别。
  • 您可能应该阅读这篇博文:blogs.msdn.com/b/shawnhar/archive/2007/07/02/… 问题不在于new,而是它触发垃圾收集的可能性。 (new 本身非常快。)

标签: c# performance xna new-operator


【解决方案1】:

new的费用分为三部分:

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

如果不在主代码中创建 any 新对象,就很难以惯用方式使用 C#...尽管我敢说通过尽可能多地重用对象是可行的。尝试使用一些真实的设备,看看你的游戏表现如何。

我当然同意像这样的微优化通常在编程中应该避免,但它更可能适用于游戏循环而不是其他地方 - 因为显然游戏对甚至小停顿。但是,很难判断使用更多对象的成本,因为 GC 成本会随着时间的推移而分散。

.NET 中的分配器和垃圾收集器非常好,尽管它在设备上可能更简单(我假设是 Windows Phone 7)?特别是,我不确定 Compact Framework CLR(这是 WP7 使用的一个)是否具有分代 GC。

【讨论】:

  • Compact Framework 没有分代垃圾回收——至少,上次我检查过。但那是在 2003 年的 PocketPC 时代,当时大多数设备只有 32MB 的内存......
  • @Rei:是的,旧版本肯定没有。不确定 3.7,这是 WP7 中的内容。
  • 嗯,设计一个实验来找出答案会很酷。不过这将是一个挑战。
  • @JonSkeet:Singleton 的使用可以帮助避免创建太多对象吗?
  • @MagB:是的,但它的不灵活性在大多数情况下仍然值得避免,IMO。
【解决方案2】:

C# 中的分配实际上比 C++ 中的要快。它只涉及增加堆指针并返回该指针。通常,对象在 C# 中比在 C++ 中更频繁地出现 newed,因为像 strings 这样的东西涉及更多的不变性。

正如其他人所指出的,真正的野兽是垃圾收集器,这有点难以分析。尽管如此,在大多数情况下,即使 GCing 也与 C++ 中的 delete 一样快(如果不快的话)——只是你无法预测它何时会发生。

.NET 团队的性能专家 Rico Mariani 的一些提示:http://msdn.microsoft.com/en-us/library/ms973837.aspx

它有点老了,对 GC 有一些改进,但大部分信息仍然相关。

我应该补充一点,XNA/Compact Framework 垃圾收集器比 x86 版本要慢一些,以牺牲 CPU 来换取内存性能,所以您应该注意这一点。

编辑

我忘了提,这很重要:value types,包括结构,也使用new 语法,但是它们是在堆栈上而不是在堆上创建的,因此除非这些结构没有 GC 成本你box他们。

【讨论】:

  • +1 对 GC 进行了很好的讨论,并且是正确的。游戏中内存分配的最大问题是垃圾收集器会停止所有线程进行收集。这很容易导致帧率中断。
  • 是的,有多种可用的 GC 实现可以解决这个问题。在 Windows 上,有 IIS 使用的服务器 GC 和 .exes 默认使用的应用程序 GC。服务器更彻底,频率更低,但锁定所有线程的时间更长。如果我们幸运的话,他们会调整 CF/XNA 的频率更高且锁定时间更短。
  • 不确定电话。但 Xbox 360 每 1MB 分配运行一次,并且是非分代的。它足够慢,你需要关心它。另一方面,在大多数情况下,Windows 都可以用于游戏开发。
  • 当然需要收集栈上包含引用的值类型;不是因为它可能已经死了,而是因为它包含的引用可能还活着。包含引用类型的堆栈分配值类型仍然会为 GC 贡献成本。
【解决方案3】:

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

【讨论】:

    【解决方案4】:

    您应该始终以“最简单”的方式编写代码然后测量瓶颈,如果它们存在。

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

    编辑

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

    【讨论】:

    • Afaik Caesar IV 至少部分是用 C# 编写的 - 太可怕了,就好像你能分辨出 GC 何时运行 :)
    • 如果 OP 正在为 WP7 开发,那么唯一的其他选择是 VB。这就是你想要的吗?!?
    • 您不仅担心移动应用的瓶颈,还担心电池消耗。
    • @Armen - 快速谷歌搜索告诉我它使用 C# 进行游戏逻辑,如果应用得当(jitted),与使用 Lua 等脚本语言相比,其性能提升或虚幻脚本。
    【解决方案5】:

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

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

    【讨论】:

      【解决方案6】:

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

      See Post By Eric Lippert

      【讨论】:

        【解决方案7】:

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

        【讨论】:

          【解决方案8】:

          当您在 c# 中编写 new 时,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.
          }
          

          【讨论】:

            【解决方案9】:

            通常,对于 c# 来说,错过 Rect、Point 等微结构的堆栈分配是一个性能黑洞。堆栈上的空间分配只是 bp:sp = bp:sp + cpu 的大小,而使用 New 的堆分配需要很多算法、gc 控制、大内存页面大小、最终在磁盘上、重定位等

            【讨论】:

              【解决方案10】:

              我的测量表明,“新”引用类型有时可能需要长达 2.2 秒,有时可能快到几个滴答声。底线是 .net GC 中没有实时保证,性能可能会以随机方式显着变化。所以我建议实时设计,例如游戏,不要在代码的实时部分(例如更新循环)中调用“new”来引用类型,因为没有实时保证。

              当然,许多人会争辩说,“新”多久会花费 2.2 秒,如果只发生几个小时一次,这是否重要。好吧,这必须是设计师的判断。但是为了学术争论,GC不是实时的,因此不要在实时代码中调用“new”。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2010-10-26
                • 1970-01-01
                • 2010-10-01
                • 2014-04-30
                • 2021-06-09
                • 1970-01-01
                • 2011-10-04
                • 1970-01-01
                相关资源
                最近更新 更多