针对大型数组的 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# 版本中获得了正好 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()
。你真的在乎它使用了多少内存吗?似乎速度更重要。如果您有内存限制,则可以设置程序在垃圾回收之前将使用的内存量。