【问题标题】:gradual GC calls渐进式 GC 调用
【发布时间】:2012-04-09 21:34:33
【问题描述】:

有没有一种有效的方法可以将数组的部分内存返回给系统? 我正在使用 C# 遍历一个大字符串数组和一个包含(> 100k 个元素)的哈希表,并且在我完成它们后将单个元素设置为 null。我已经尝试在各个级别和整个循环中调用垃圾收集器,但它们都没有将内存返回给系统(完全调用垃圾收集器并等待挂起的终结器会导致我的代码变得非常缓慢且无响应)。
我曾考虑将数组拆分为 n 个部分,并在每个部分完成后调用 gc,但这看起来很乱

GC.Collect(1);
GC.Collect(2);
....
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();

【问题讨论】:

  • 可能最好的办法是让 GC 完成它的工作。将引用设置为 null 绰绰有余。
  • @HenkHolterman 好的 :) 我想问也无妨。如果我没有得到任何答案,我会删除问题:)
  • 假设没有其他对对象的实时引用。此外,如果它们足够大,它们可能会被分配到大型对象堆上,并且您可能会看到碎片。
  • @caseyr547,完全没有必要删除问题...
  • @EdS。谢谢,如果它们位于大型对象堆上,那将是有意义的,我关于多个数组的想法会修复内存泄漏吗?

标签: c# arrays memory-management hashtable


【解决方案1】:

让垃圾收集器做它的事。最有效的方法正是 GC 已经做的:推迟收集,直到它们真正需要完成。这样一来,它就不必进行不必要的收集,并且所有内存回收工作都可以集中到相对较少的收集调用中,因此它不必过于频繁地遍历对象图。

只需确保清除对对象的所有引用,这样您就不会意外地使其存活时间超过必要的时间,但只要您这样做,您就不需要做任何其他事情。

【讨论】:

    【解决方案2】:

    除了一些非常具体和例外的情况外,最好的策略是让垃圾收集器按照自己的时间表运行。这是一款经过高度优化的软件,对 CLR 的内部工作原理的了解比您或我多得多,而且几乎总是会做出比我们更好的决策。

    如果您在处理完对象后担心对象所消耗的内存,则可以在完成对它们的处理时将各个数组元素清空(可能会更快地收集对象)。

    更重要的是,是否需要一次将所有数据保存在内存中?是否可以一次只加载一点 - 例如,从文件中增量读取?如果是这样,您绝对可以选择用IEnumerable<T> 替换您的数组,这样您就可以根据需要延迟加载数据,并在完成后自动忘记它。这种方法可以保证降低您的内存消耗,但代价是一些额外的计算。

    【讨论】:

      【解决方案3】:

      如果您将字符串存储在一个数组中,那么当您遍历它们时,它们都将保留在内存中。

      实际的迭代不会大幅增加内存压力:您创建的任何新对象都将被有效地进行垃圾回收。

      对于数组的特定情况,您可以在读取数组条目后将它们设置为null。我建议反对它:如果您在迭代开始时没有出现内存不足的问题,那么您可能也会在其余部分中幸存下来。 一旦您不再需要它,请确保将 all 对数组的引用清空。在调试时,您可以在您认为不再引用该数组的位置添加 GC.Collect()。您应该观察到分配的内存大幅下降。如果这没有发生,那么您在其他地方有更多对数组的引用,或对数组内容的引用。

      对于哈希表,这种方法根本行不通。在迭代它们时,您无法安全地从哈希表中删除条目。

      现在,如果您使用的是哈希表,这意味着您并不真正关心项目的顺序。在这种情况下,您可以重新设计算法以在读取数据时对其进行处理,而无需将其保留在数组或哈希表中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-09-27
        • 1970-01-01
        • 2013-01-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多