繁体   English   中英

为什么重用数组会在c#中显着提高性能?

[英]Why does reusing arrays increase performance so significantly in c#?

在我的代码中,我执行了大量任务,每个任务都需要大量内存来临时存储数据。 我有大约500个任务。 在每个任务开始时,我为数组分配内存:

double[] tempDoubleArray = new double[M];

M是一个很大的数字,取决于精确的任务,通常大约2000000.现在,我做一些复杂的计算来填充数组,最后我使用数组来确定这个任务的结果。 之后,tempDoubleArray超出范围。

分析表明构造数组的调用非常耗时。 因此,我决定尝试重用数组,使其静态并重用它。 它需要一些额外的杂耍来计算出阵列的最小尺寸,需要额外通过所有任务,但它可以工作。 现在,程序更快(从80秒到22秒执行所有任务)。

double[] tempDoubleArray = staticDoubleArray;

但是,我有点不知道为什么这种方法运作得很好。 我想在原始代码中,当tempDoubleArray超出范围时,可以收集它,所以分配一个新数组应该不那么难吗?

我问这个是因为了解它的工作原理可能有助于我找出实现相同效果的其他方法,并且因为我想知道在什么情况下分配会产生性能问题。

仅仅因为可以收集某些东西并不意味着它会。 事实上,如果垃圾收集器像其收集中那样具有攻击性,那么你的性能会明显变差。

请记住,创建数组不仅仅是创建一个变量,而是创建N变量( N是数组中元素的数量)。 尽管你必须小心谨慎,但重复使用数组是提高性能的良好方法。

为了澄清,我的意思是“创建变量”具体是为它们分配空间并执行运行时所具有的任何步骤以使它们可用(即将值初始化为零/ null)。 因为数组是引用类型,所以它们存储在堆上,这使得在内存分配方面生活变得复杂一些。 根据数组的大小(无论它在总存储空间中是否超过85KB),它将存储在普通堆或大对象堆中。 与所有其他堆对象一样,存储在普通堆上的数组可以触发堆的垃圾收集和压缩(这涉及在当前正在使用的内存中进行混洗以最大化连续的可用空间)。 存储在大对象堆上的数组不会触发压缩(因为LOH从未被压缩),但它可能通过占用另一个大的连续内存块来触发过早收集。

一个答案可能是大对象堆 - 大于85KB的对象分配在不同的LOH上,不经常收集而不是压缩。

请参阅有关性能影响的部分

  • 有分配成本(主要是清除分配的内存)
  • 收集成本(LOH和Gen2收集在一起 - 导致Gen2中大型对象的压缩)

在存在碎片的情况下分配大块内存并不总是容易的。 我不能肯定地说,但我的猜测是它必须做一些重新安排才能为这么大的内存块获得足够的连续内存。 至于为什么分配后续数组的速度并不快,我的猜测是大块在GC时间和下一次分配之间分段,或者原始块从未GCd开始。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM