线程内存泄漏

Posted

技术标签:

【中文标题】线程内存泄漏【英文标题】:Thread memory leak 【发布时间】:2014-10-29 21:49:02 【问题描述】:

我正在尝试在一个生成多个线程的大型 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 清理它,但这似乎并没有发生。我一定不能在这里理解更深层次的东西,我希望能在修复此泄漏方面提供一些帮助。提前致谢!

【问题讨论】:

【参考方案1】:

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

设计选择非常大胆,CLR 每个线程使用 5 个操作系统对象。管道,用于同步。这些对象本身是一次性的,设计选择是使 Thread 类实现 IDisposable。这对 .NET 程序员来说是相当困难的,很难在正确的时间进行 Dispose() 调用。顺便说一句,Task 类设计中没有表现出的勇气,引起了很多麻烦和general advice not to bother。

不是在精心设计的 .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。

【讨论】:

谢谢你!当您不想计划太多时,这对于 .net 中的一次性多线程 http 蜘蛛非常有用。 ;)

以上是关于线程内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

线程内存泄漏

创建大量线程时.Net内存泄漏

ThreadLocal 和内存泄漏

Android线程内存泄漏

java多线程--------深入分析 ThreadLocal 内存泄漏问题

ThreadLocal和内存泄漏