C#大型阵列的内存优化

时间:2011-05-21 23:39:04

标签: c# c++ optimization performance

以下是c ++和c#中的两个代码部分完全相同:

C ++
http://ideone.com/UfL5R

#include <stdio.h>
int main(int argc, char *argv[]) {
  char p[1000000];
  unsigned int i,j;
  unsigned long long s=0;
  for(i=2;i<1000000;i++) p[i]=1;
  for(i=2;i<500000;) {
    for(j=2*i;j<1000000;j+=i) p[j]=0;
    for(i++;!p[i];i++);
  }
  for(i=3,s=2;i<1000000;i+=2) if(p[i]) s+=i;
  printf ("%lld\n",s);
  return 0;
}

时间:0.01s memmory:2576 kB

C#
http://ideone.com/baXYm

using System;

namespace ConsoleApplication4
{
    internal class Program
    {
        private  static void Main(string[] args)
        {
            var p = new byte[1000000];
            ulong i, j;
            double s = 0;
            for(i=2;i<1000000;i++) 
                p[i]=1;

            for(i=2;i<500000;) 
            {
                for(j=2*i;j<1000000;j+=i) 
                    p[j]=0;
                for(i++;p[i]==0;i++);
            }

            for(i=3,s=2;i<1000000;i+=2) 
                if(p[i]!=0) s+=i;

            Console.WriteLine(s);
        }
    }
}

时间:0.05s mem:38288 kB

如何改进C#代码以证明C#对我的同事来说可以和C ++一样快?

正如您所看到的,C#执行时间大5倍,内存消耗大15倍。

5 个答案:

答案 0 :(得分:9)

在发布模式下编译并运行。在构建并在发布模式下运行时,我从C#版本获得0.01s。就内存消耗而言,您正在将苹果与橙子进行比较。托管环境将占用更多内存,因为它托管CLR和垃圾收集器,而这些内存并非免费。

答案 1 :(得分:6)

  

如何改进C#代码以证明C#对我的同事来说可以和C ++一样快?

你做不到。有一些合法的领域,C ++从根本上比C#更快。但也有一些领域,C#代码将比同等的C ++代码表现更好。他们是不同的语言,有不同的优点和缺点。

但作为程序员,你真的应该把你的决定建立在逻辑上。

逻辑规定您应首先收集信息,然后根据该信息做出决定。

相反,您决定首先,然后寻找支持它的信息。 如果你是一名政治家,那可能会奏效,但这不是编写软件的好方法。

不要去寻找C#比C ++更快的证据。相反,检查哪个选项在您的情况下更快

在任何情况下,如果你想证明X可以和Y一样快,你必须按照常规的方式去做:让X和Y一样快。和往常一样,在进行性能调整时,一个分析器就是你的最好的朋友。找出确切花费额外时间的地方,然后弄清楚如何消除它。

但内存使用是一个失败的原因。 .NET只使用更多内存,原因如下:

  • 它有一个更大的运行时库,必须存在于进程的“地址空间”
  • .NET对象具有C ++类中不存在的其他成员,因此它们使用更多内存
  • 垃圾收集器意味着你通常会有一些“不再使用但尚未回收”的内存。在C ++中,通常会立即释放内存。在.NET中它不是。 .NET基于内存便宜的假设(通常是正确的)

答案 2 :(得分:4)

如何极大地提高C#代码的性能

为此做“不安全”(非托管)...每次你做someSortOfArray[i]时,.NET框架都会做各种各样的事情(例如越界检查)准时。

这真的是非托管(然后使用指针和执行myPointer ++)的重点。

只是为了澄清,如果你不受管理,然后仍然做for-loop并做someArray[i],你就什么都没有保存。

另一个S.O.可能有助于您的问题:True Unsafe Code Performance

声明

顺便说一下,我并不是说要一直这样做,而是仅作为这个特定问题的答案。

答案 3 :(得分:3)

请注意您的时间安排。它没有显示,你是如何测量执行时间的。人们可以期待启动时.NET应用程序的合理开销。因此,如果您只关注循环的执行时间,则应该运行内部循环几次(多次),跳过1..2次迭代,测量其他迭代并计算平均值。

我希望结果比...更相似。但是,一如既往地针对“峰值性能” - 有关内存管理的预防措施非常重要。在这里,防止测量功能内部的“新”可能就足够了。在每次迭代中重用p []。

答案 4 :(得分:1)

内存使用量可能与垃圾回收有关。在Java中,内存使用量有意高 - 垃圾收集只在需要更多内存时才会发生。这是出于速度原因,因此C#做同样的事情是有意义的。您不应该在发布代码中执行此操作,但为了显示您实际使用的大量内存,可以在测量内存使用量之前调用GC.Collect()。你真的关心它使用了多少内存吗?似乎速度更重要。如果你有内存限制,你可以设置程序在垃圾收集之前使用的内存量。