线程内存泄漏

我试图在更大的C#程序中追踪内存泄漏,该程序产生多个线程。 在这个过程中,我创建了一个小方程序,我用它来测试一些基本的东西,我发现了一些我真的不明白的行为。

class Program { static void test() { } static void Main(string[] args) { while (true) { Thread test_thread = new Thread(() => test()); test_thread.Start(); Thread.Sleep(20); } } } 

运行这个程序,我看到程序的内存使用量稳步增加而不会停止。 在短短几分钟内,内存使用量超过100MB并继续攀升。 如果我注释掉test_thread.Start();行,那么程序使用的内存最大可以达到几兆字节,并且会升级。 我还尝试使用GC.Collect()在while循环结束时强制进行垃圾收集,但它似乎没有做任何事情。

我认为一旦函数完成执行允许GC将其拖拽,线程就会被取消引用,但这似乎并没有发生。 我不能在这里深入了解一些事情,我会很感激帮助解决这个问题。 提前致谢!

这是设计使然,您的测试程序应该显示内存使用失控。 您可以从Taskmgr.exe中查看根本原因。 使用View + Select Columns并勾选“Handles”。 观察过程的句柄数量是如何稳步增加的。 内存使用量随之增加,反映了句柄对象使用的非托管内存。

设计选择非常勇敢,CLR每个线程使用5个操作系统对象。 管道,用于同步。 这些对象本身是一次性的,设计选择是不要使Thread类实现IDisposable。 这对.NET程序员来说非常困难,很难在正确的时间进行Dispose()调用。 在任务类设计中没有表现出来的勇气,导致大量的手工拧干和一般建议不要打扰 。

在精心设计的.NET程序中,这通常不是问题。 GC运行的频率足以清理那些OS对象。 并且Thread对象正在谨慎地创建,使用ThreadPool来执行非常短的运行线程,就像测试程序使用的那样。

它可以,我们看不到你的真实节目。 请注意从这样的综合测试中得出太多结论。 您可以使用Perfmon.exe查看GC统计信息,让您了解它是否运行得足够频繁。 一个体面的.NET内存分析器是首选的武器。 GC.Collect()是备用武器。 例如:

 static void Main(string[] args) { int cnt = 0; while (true) { Thread test_thread = new Thread(() => test()); test_thread.Start(); if (++cnt % 256 == 0) GC.Collect(); Thread.Sleep(20); } } 

而且你会看到它现在来回反弹,永远不会超过4 MB。