C#的内存使用过多

时间:2018-08-23 13:41:36

标签: c# memory-management idisposable

我有一个处理多个步骤的过程。 (假设是一种策略模式的通用实现),其中所有步骤都在传递一个通用的ProcessParameter对象。 (对其进行读/写)

此ProcessParameter是一个具有许多数组和集合的对象。示例:

class ProcessParameter() {
   public List<int> NumbersAllStepsNeed {get; set;}
   public List<int> OhterNumbersAllStepsNeed {get; set;}
   public List<double> SomeOtherData {get; set;}
   public List<string> NeedThisToo {get; set;}
   ...
}

步骤完成后,我想确保释放内存而不是闲逛,因为这可能占用大量内存,并且其他进程也需要运行。

我可以通过运行以下命令来做到这一点:

pParams.NumbersAllStepsNeed = null;
pParams.OhterNumbersAllStepsNeed = null;
pParams.SomeOtherData = null;
...

或者ProcessParameter实现IDosposable,而Dispose方法可以做到这一点,那么我只需要使用pParams.Dispose()(或将其包装在using块中)

清除一个正在运行的进程的已用数据的内存占用的最好,最优雅的方法是什么?

使用数组而不是列表会改变任何东西吗?还是混合? 我需要的实际参数类型是自定义对象的集合/数组。

我朝着正确的方向看吗?

更新

好问题!感谢您的评论! 我曾经让这个过程单次运行,我可以看到内存使用率很高,然后逐渐下降到“正常”。

当我开始使用不同的声明参数将这些进程彼此链接在一起时,问题就来了。那是内存过高的时候,所以我想在两个进程之间包括一个清理步骤,并寻找最佳的实现方法。

有一个数据库,这种参数是一种“缓存”,可以加快处理速度。

关于IDisposable的要点,我不在params对象中保留非托管资源。

1 个答案:

答案 0 :(得分:1)

虽然使用Disposal模式是一个好主意,但我认为它在释放内存方面不会给您带来任何额外的好处。

可能有两件事:

  1. 致电GC.Collect()

但是,我真的不会打扰(除非您可能会遇到内存异常)。显式调用GC.Collect()可能会损害性能,并且垃圾回收器确实确实可以很好地完成工作。 (但请参见下面的LOH。)

  1. 注意大对象堆(LOH)

您提到它使用了“大内存占用”。请注意,任何85,000字节或以上的单个内存分配都来自大对象堆(LOH)。 LOH不会像小对象堆那样被压缩。即使您有足够的可用内存,这也会导致LOH碎片化,并可能导致内存不足错误。

您何时会迷路到LOH?任何85,000字节或更多字节的内存分配,因此在64位系统上将是具有10,625个或更多元素的任何数组(或列表或字典),图像处理,大字符串等。

三种有助于最大程度地减少LOH碎片的策略:

i。重新设计以避免它。并不总是实用的。但是列表列表或词典可能会避免这种限制。这会使实施变得更加复杂,因此除非您确实需要,否则我不会这样做,但是从正面来看,这可能非常有效。

ii。使用固定尺寸。如果您在LOH中的所有其他内存分配都具有相同的大小,则这将有助于最大程度地减少碎片。例如,对于字典和列表,将容量(设置内部阵列的大小)设置为您可能使用的最大大小。如果您要进行图像处理,则不太实用。

iii。强制垃圾收集器压缩LOH:

    start_date   end_date  value
1.0 2018-01-01 2018-01-31     17

您确实需要使用.NET Framework 4.5.1或更高版本才能使用它。 这可能是最简单的方法。在我自己的应用程序中,我有几个实例,我知道我会迷路到LOH中,而碎片化可能是一个问题,我设置了

System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;   
GC.Collect();

作为析构函数中的标准-但只有在分配时遇到内存不足异常时,才显式调用GC.Collect()。

希望这会有所帮助。