针对大型数组的 C# 内存优化

本文关键字:内存 优化 数组 大型 | 更新日期: 2023-09-27 17:57:06

这是 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 内存: 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 内存: 38288 KB

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

如您所见,C# 执行时间大 5 倍,内存消耗大 15 倍。

针对大型数组的 C# 内存优化

在发布模式下编译和运行。在发布模式下构建和运行时,我从 C# 版本中获得了正好 0.01 秒。就内存消耗而言,您正在比较苹果和橙子。托管环境将消耗更多内存,因为它托管 CLR 和垃圾回收器,这并非没有成本。

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

为此去"不安全"(不受管理)...每次你做someSortOfArray[i],.NET 框架都在做各种占用时间的整洁的事情(例如越界检查)。

这确实是非托管的全部意义(然后使用指针并执行myPointer++)。

澄清一下,如果你不受管理,然后仍然做一个for-loop并做someArray[i],你什么也没保存。

另一个可能对您有所帮助的 SO 问题:真正的不安全代码性能

免責聲明

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

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

你不能。在某些合法领域,C++从根本上比 C# 更快。但也有一些地方 C# 代码的性能会比等效的 C++ 代码更好。它们是不同的语言,具有不同的优势和劣势。

但是作为一个程序员,你真的应该根据逻辑来做决定。

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

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

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

无论如何,如果你想证明X可以和Y一样快,你必须用通常的方式去做:让X和Y一样快。与往常一样,在进行性能调优时,探查器是您最好的朋友。找出额外时间花费的确切位置,然后找出如何消除它。

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

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

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

我希望结果比。但是,与往常一样,当以"峰值性能"为目标时,有关内存管理的预防措施很重要。在这里,防止测量功能内部的"新"可能就足够了。在每次迭代中重用 p[]。

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