垃圾收集不会减少当前内存使用量 - 在发布模式下。为什么?

时间:2009-05-20 14:29:46

标签: .net garbage-collection

我构建了一个快速程序,需要遍历一个巨大的日志文件(几百万条记录),并从内部找到各种各样的零碎。由于数据量如此巨大,我一直很想看看我的Windows任务管理器性能选项卡,看看有多少CPU和内存被使用。

程序成功获得结果后,显然CPU使用率会下降。但在看完我的内存使用量后,在执行过程中缓慢上升到几千兆字节,它保持不变。

我试图在我的函数结束时调用GC.Collect(),尝试将事物设置为null,尝试在发布模式下运行程序(我听说GC.Collect()可能无法正常工作,因为我想要它到调试模式)。

如果我关闭程序,内存使用率会下降,但我无法弄清楚为什么在应用程序生命周期内无法清理我的应用程序。在一天结束时,这是一个一次性的应用程序,但我只是想知道我错过了什么,即什么保留了所有这些记忆。

思想?

10 个答案:

答案 0 :(得分:9)

调用GC.Collect()只是一个收集垃圾的请求,它不是一个订单,所以如果它认为合适,CLR可以选择忽略该请求。

例如,如果有很多垃圾在收集时会导致明显的延迟,但是仍有空闲内存可以为后续分配提供服务,那么GC可能会选择忽略您的请求。

答案 1 :(得分:6)

有一种方法。我发现这篇文章,它是西班牙语,确定你理解代码,它的工作原理,我测试过 [http://www.nerdcoder.com/c-net-forzar-liberacion-de-memoria-de-nuestras-aplicaciones/][1]

[DllImport("kernel32.dll", EntryPoint = "SetProcessWorkingSetSize", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)]
private static extern int SetProcessWorkingSetSize(IntPtr process, int minimumWorkingSetSize, int maximumWorkingSetSize);
public static void alzheimer()
{
    GC.Collect();
    GC.WaitForPendingFinalizers();
    SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
}

答案 2 :(得分:5)

您的对象可能仍然以某种方式生根。您可以尝试使用内存分析器来查看是否是这种情况。我通常建议SciTech的.NET Memory Profiler执行此操作,但Red-Gate也有decent memory profiler。 SciTech和Red-Gate都有试用版。也可以使用WinDBG with SOS

所有个人资料here都有一个过时的列表。

答案 3 :(得分:4)

许多内存分配器(带或不带垃圾回收)通常“​​囤积”他们释放的内存,而不是将其返回给操作系统,这是正常的,因为在许多情况下,刚刚释放的内存将再次被请求并且将它保持在流程中更快,而不是继续给它并一次又一次地向操作系统询问它(由于页面对齐问题等原因,还需要额外的努力)。

在你提到的一次性应用中,这不是问题。当我有一个长期运行的应用程序,我所知道将是一个瞬态需要大量的内存,我使用的一种方法是产生一个子进程来执行内存饥饿的东西,因为当该进程结束操作系统收回内存。在Unix系统(只是分叉)上它更容易,但在Windows上也不会太糟糕,如果有保证的话。

答案 4 :(得分:3)

当您调用Collect()时,无法保证垃圾收集器运行。它只是标记要收集的对象。 GC下次运行时,它将“收集”标记的对象。

.NET中没有办法强制GC在特定时间点收集 - 如果您需要此功能,则需要转到本机代码。

答案 5 :(得分:2)

不要忘记CLR最终使用Windows内核中的底层内存管理器,它可能有自己的关于何时释放内存的策略。例如,如果您使用的内存来自池,则可能只是将其返回到池中,而不是在用户级别释放它时取消分配。因此,完全有可能存在(并且可能会存在)应用程序占用的内存量与分配给该进程的内存量之间的差异。

答案 6 :(得分:1)

Collect方法不保证回收所有无法访问的内存。

答案 7 :(得分:1)

强制GC.Collect进行收集,像这样调用它 GC.Collect的(2); 这意味着您要求GC为整个堆执行完全阻塞GC,2表示堆的第2代。

答案 8 :(得分:0)

您应该查看CLR堆大小的性能计数器,而不是分配给任务管理器中显示的进程的总内存。 Windows不会回收分配给进程的内存,除非整个系统缺乏内存,即使进程没有使用内存也是如此。

答案 9 :(得分:0)

循环中使用的任何对象是否实现了IDisposable?