【问题标题】:Calling GC.Collect inside loop and thread and Clearing collection doesn't decrease memory usage在循环和线程内调用 GC.Collect 并清除集合不会减少内存使用量
【发布时间】:2013-11-25 02:48:22
【问题描述】:

我有很多对象,每个对象都有很多成员,我需要在每个成员中插入一些集合数据,并在使用它们后再次清除它们.. 清除后我希望 GC.Collect() 可以立即申请内存使用,但它的外观并没有减少内存使用量。我检查过任务管理器总是在增加。只有在所有处理任务完成后,我才注意到内存使用量下降了。

在我的电脑上内存使用率达到了 10G 几乎 100%.. 并且只有在所有处理完成后才会下降.. 我担心如果客户端电脑内存不足会导致内存不足异常

我注意到清除所有收集数据看起来并没有减少内存使用量。 我应该如何收回记忆?

在线程内的循环内调用 GC.Collect 可以吗?

插图看起来像这样。 例如:

public class Progress 
{
   var obj2 = new Obj2();

   public void Processing()
   {
       //here my thread start.. (I have some thread class)
       AsyncClass.DoTask(() =>
       {
           foreach(var curProcess in AllObjects)
           {

             var allSolutions = (from m in curProcess.memories
                               where.... 
                               select m).ToList();

            forearch(var memory in allSolutions)
            {  
               foreach(data in alldata)
               {
                 //some process
                 ...
                 ...
                 result = data.result;

                 //pushing the data into memory members obj
                  obj2.PushCalculation(memory, result)
               }
             }

            forearch(var memory in allSolutions)
            {  
                obj2.ClearValues(memory)
            }

             GC.Collect();
             GC.WaitForPendingFinalizers();
         }
      });
    }
  }

  public class Obj2 : IDisposable
  {
    public void PushCalculation(memoryObj mem, List<data> results)
    {
       foreach(var result in results)
       {
          mem.data1.add(result);
          mem.data2.addrange(result * 1);
            //etc... all about pushing into memory object members
       }
    }

    public void ClearValues(memoryObj mem)
    {
       // clear all collections of memoryObj members 

       mem.data1.Clear();
       mem.data1 = null;

       mem.data2.Clear();
       mem.data2 = null;

       ...... 
       ......
    }

  }

【问题讨论】:

  • 这些物品是一次性的,您是否正在处理它们?
  • 在您的处理完成之前内存使用量不会下降的事实告诉我没有要收集的垃圾。垃圾回收并不是一个神奇的“缩小我的内存使用量”功能。
  • @Raymond Chen,清除动态集合不会释放一些内存使用吗?
  • 垃圾收集无法释放仍可访问的内存。这会导致崩溃。
  • 此外,没有理由假设任务管理器报告的任何内存统计信息与托管堆的大小有任何关系。大多数人甚至不明白任务管理器中报告的“内存大小”是什么意思。

标签: c# memory garbage-collection


【解决方案1】:

首先:您应该让垃圾收集器 (GC) 完成它的工作。根据系统、当前负载、应用程序配置文件和其他因素,它可能比您更好地判断何时收集垃圾。

第二:垃圾收集器分配一些内存空间进行操作。即使收集器正确收集了大部分空间,该空间也可能不会缩小。然后它是空的,但可用于将来的分配;或者它可能会在以后的某个时间点缩小。

但如果垃圾收集器实际上无法收集您的某些对象,那么您仍然在某处引用了这些对象。也许在静态字段中,或者您忘记的集合中?

你应该从中得到的是:永远不要致电GC.Collect()。致电GC.Collect() 的理由很少。如果您有一些内存问题提示您使用GC.Collect(),那么您应该调查导致内存问题的原因。

我能想到的可能原因:

  • 保留对不再需要的对象的引用。
  • 使用非托管资源后未正确处置。

【讨论】:

  • 感谢您的回答,我同意,实际上我不打算在第一次调用 GC.Collect .. 但只是因为我很好奇为什么内存不能立即收回,我只注意到一个事件代表但我已经主动分离它们,清除值“-=”之前的事件......并且没有使用未管理的资源......只是注意将值清除到集合中并不意味着减少内存使用量?......
【解决方案2】:

垃圾收集器是复杂的野兽,它们界面的简单性具有欺骗性。直接打GC.Collect()吧?

.NET 垃圾收集器是一个分代 GC。当它运行时,它会首先查找要删除的 new 对象。这是因为绝大多数物体都是短暂的。幸存的对象被放置到不同的内存池中,并且不会经常扫描该池。如果我没记错的话,有三个这样的池。这意味着当 GC 运行时,它不会扫描整个堆。

另请注意,这些是。这意味着当虚拟机想要分配内存时,它会在尝试扩展堆之前先在池中查找空闲内存。这只有在收集的对象的内存没有立即回收时才有可能。也就是说,GC收集对象时,并不一定会将内存归还给操作系统。

这将我们引向GC.Collect()。我们知道 GC 运行时不会扫描整个堆,销毁对象时也不会返回内存。那么,拨打GC.Collect() 有什么意义呢?我不能回答那个。就我而言,打电话给GC.Collect() 没有用。

【讨论】:

    【解决方案3】:

    您的代码可能不是真实的,但我还是会尝试回答。

    当您调用PushCalculation 时,会将指向data 类对象的指针(假设data 不是结构)添加到mem.data1mem.data2 集合中。因此,在该操作之后,您对每个数据对象都有两个引用。一个来自mem.data,另一个来自data.results

    然后在ClearValues 中清除每个data 对象中的一个引用,但results 仍将它们全部固定。如果您希望垃圾收集器释放内存,您还需要清除 data.results

    换句话说,您有内存泄漏。请参阅此答案以了解如何调查内存泄漏。 How to debug the potential memory leak? 我个人使用过 WinDbg,发现它非常有用。它显示了在内存中锁定对象的原因

    【讨论】:

      猜你喜欢
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-02
      • 2019-01-23
      • 2017-05-19
      相关资源
      最近更新 更多