【问题标题】:Memory leaks while using array of double使用双精度数组时内存泄漏
【发布时间】:2010-05-06 19:57:49
【问题描述】:

我有一部分代码在 double 的大数组上运行(至少包含大约 6000 个元素)并执行数百次(通常是 800 次)。

当我使用标准循环时,像这样:

double[] singleRow = new double[6000];
int maxI = 800;
for(int i=0; i<maxI; i++)
{
singleRow = someObject.producesOutput();
//...
// do something with singleRow
// ...
}

内存使用量增加了大约 40MB(从循环开始时的 40MB,到结束时的 80MB)。

当我在每次迭代时强制使用垃圾收集器执行时,内存使用量保持在 40MB 的水平(上升并不显着)。

double[] singleRow = new double[6000];
int maxI = 800;
for(int i=0; i<maxI; i++)
{
singleRow = someObject.producesOutput();
//...
// do something with singleRow
// ...
GC.Collect()
}

但是执行时间要长3倍! (很重要)

如何强制 C# 使用相同的内存区域而不是分配新的内存区域? 注:someObject类的代码我是有权限的,如果需要,我可以修改。

【问题讨论】:

  • 如果可能的话,我想看看你得到数组后如何处理它,以及producesOutput 是如何工作的。

标签: c# memory-management


【解决方案1】:

为什么要分配一个大的空singleRow 只是为了覆盖它?也许您应该传入数组以修改其值。这将允许您重复使用它。

double[] singleRow = new double[6000];
int maxI = 800;
for(int i=0; i<maxI; i++)
{
    someObject.FillWithOutput(singleRow);
    //...
    // do something with singleRow
    // ...
}

如果该方法有时填充少于 6000 个元素,它可以简单地返回填充计数。或者,您可以使用 List&lt;double&gt;,这将允许调整大小。

【讨论】:

    【解决方案2】:

    singleRow设为参数,每次都将其传递给对producesOutput的调用...

    基本上您的producesOutput 方法可能每次都分配一个新数组,而重新分配singleRow 只是将旧内存标记为可用 删除,但不会运行GC 出于性能原因。

    【讨论】:

    • 如果数组是固定长度的,则无需将其设为 ref。
    • 可以说,ref 不会造成直接伤害,并且会显示出修改参数的意图。不过,我认为这不是正确的做法。
    • @Steven,使用 ref 似乎更清楚一点。 @John,感谢您的帮助。可惜我不能接受两个答案;)
    • 好吧,如果要替换阵列而不是原地修改阵列,则需要ref。由于您确实想就地修改,ref 可能会产生误导。更深层次的困惑是它允许该方法做一些它实际上从未做过的事情。 (我也赞成约翰的回答。)
    • 我需要检查我们项目中使用的约定。我想我会给 ref 留下适当的评论来解释用法。
    【解决方案3】:

    你不会喜欢这样,但如果你必须强制 GC,你就做错了。请记住,内存可能会增长,直到有触发 GC 的压力 - 这是一件好事,因为这意味着 GC 直到它必须运行时才会运行。

    这是一个听起来很傻的测试,但它可能会对正在发生的事情有所帮助。在 FillWithOutput() 内部注释掉它的大部分功能。然后运行你的循环并测量内存。逐渐取消注释掉它的一部分,直到你看到一个亮点。现在您离导致“泄漏”的原因越来越近了。

    【讨论】:

      猜你喜欢
      • 2015-04-05
      • 1970-01-01
      • 2013-11-30
      • 2018-06-26
      • 1970-01-01
      • 2020-05-11
      • 2012-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多