【问题标题】:.NET Framework - Possible memory-leaky classes?.NET Framework - 可能的内存泄漏类?
【发布时间】:2011-02-10 07:30:49
【问题描述】:

就在前几天,我正在调查一个内存泄漏,它在不到两分钟的时间内将应用程序从 ~50MB 膨胀到 ~130MB。原来问题出在ConcurrentQueue 类上。在内部,该类存储数组的链表。当一个项目从 ConcurrentQueue 中出列时,数组中的索引会被碰撞,但该项目仍保留在数组中(即它没有设置为 null)。整个数组节点在足够的入队/出队后被丢弃,所以从技术上讲这不是一个泄漏,但如果将大对象放入 ConcurrentQueue,这可能会很快失控。文档没有注意到这种危险。

我想知道基类库中还有哪些其他潜在的内存陷阱?我知道 Substring 之一(也就是说,如果您调用 substring 并只保留结果,整个字符串仍将在内存中)。你还遇到过其他人吗?

【问题讨论】:

    标签: c# .net memory-leaks


    【解决方案1】:

    虽然不是直接的内存泄漏或特定于 .net/BCL,但存在字符串连接(使用 += 运算符)问题。由于大量垃圾收集,这在循环中会占用大量 CPU。

    【讨论】:

    • 是的。 Java 通过将其转换为使用 StringBuilder 解决了这个问题;我不知道为什么 .NET 没有这样做。
    • .NET 与 System.Text 下的内容相同
    • VS C# 编译器也很聪明,可以在内部将 ("This " + "is" + " string #" + stringNumber) 等表达式转换为 StringBuilder,如果这样做有意义的话。跨度>
    • @Dan Bryant:幸运的是你不正确。对于您提到的情况,编译器实际上会发出对string.Concat("This is string#", stringNumber) 的调用。尽可能组合文字,调用string.Concat,因为对于固定数量的追加操作,它比StringBuilder 快。
    【解决方案2】:

    你是对的。该错误位于方法System.Collections.Concurrent.ConcurrentQueue<T>+Segment.TryRemove(out T, ref ConcurrentQueue<T>.Segment)中。

    如果您在 Reflector 中查看此方法,您将看到以下行:

    result = this.m_array[low];
    

    后面应该有下面一行:

    this.m_array[low] = default(T);
    

    作为参考,您可以在System.Collections.Generic.Queue<T>.Dequeue()方法中看到这是如何正确实现的。

    【讨论】:

    • 是的;在 Reflector 中也看到了这一点——尽管我不确定 t 是否会以某种方式破坏原子性/线程?
    • 不,这绝对是一个错误。存储桶在该区域中受到保护,并且代码旨在确保它包含的值只被读取一次。
    • 顺便说一句,我最初在 4 月 1 日向 MS 的某人发送了一份报告。我只是认为他们还没有机会修复它。不幸的是,在问题解决之前,该类完全无法使用。
    • @Robert Fraser:我没有在 connect.microsoft.com 上提交它,因为当我找到它时,我所能做的就是给我的上级快速写信,然后抄送 MS 的联系人我重写了代码以改用Queue<T>
    【解决方案3】:

    ConcurrentQueue 最多只能容纳 31 个出列对象。除非您处理的是非常大的对象图,否则这应该不会造成大问题。

    无论如何,如果您没有足够的空间来分配 32 个对象,那么使用 ConcurrentQueue 是没有意义的......

    【讨论】:

    • 如果我有消息队列怎么办?如果是为了服务端socket的客户端连接,那么就有500个这样的队列呢?每个客户决定向我发送 32 条每条 10 KB 长的消息。我最终得到了 160 MB 的垃圾。如果我有 2000 个这样的客户端,或者消息变得更大,我最终会得到 OutOfMemoryException 和程序崩溃。嘿,如果我尝试重用这些糟糕的队列,并预先分配它们的负载,那么即使在套接字连接关闭后,我也会记住这些垃圾。显然,当它不泄漏时,使用这个队列是有意义的。
    猜你喜欢
    • 1970-01-01
    • 2022-10-17
    • 2011-01-03
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    相关资源
    最近更新 更多