【问题标题】:C# MemoryStream leaking memory, after disposing/close/etc?C# MemoryStream 泄漏内存,在处理/关闭/等之后?
【发布时间】:2012-03-09 20:47:04
【问题描述】:

我一直在跟踪我的应用程序中的大量内存泄漏,问题似乎出在 MemoryStream 类上。每当我使用“使用”关键字或显式关闭/处置时,垃圾收集器将永远不会收集内存。这里有什么问题?

byte[] bData = System.IO.File.ReadAllBytes( "F:\\application_exit_bw.png" );
using( System.IO.MemoryStream hMemoryStreamOutput = new System.IO.MemoryStream())
{
    for ( int i = 0; i < 10000; i++ ) hMemoryStreamOutput.Write( bData, 0, bData.Length );
}
Thread.Sleep(Timeout.Infinite);

通过显式关闭/丢弃,行为保持不变。内存已被占用,并且会一直保持这种状态,直到我关闭我的应用程序,或者应用程序填满了所有系统内存。帮忙?

【问题讨论】:

    标签: c# .net memory


    【解决方案1】:

    MemoryStream 类或示例代码中的用法没有任何问题。 .Net 中的 GC 不再在内存消失后立即清理内存。相反,当堆中的可用空间达到某个阈值或使用GC.Collect 调用显式调用时,它会回收它。

    在这种情况下,释放内存的唯一方法是在 using 语句之后和 Thread.Sleep 调用之前立即发生 GC。这不太可能发生,因此如果您对程序进行分析,当它实际上没有泄漏时,它会出现内存泄漏

    【讨论】:

      【解决方案2】:

      这是非确定性 GC 的症状。 GC 根本不保证何时释放内存。这是正常的、预期的和想要的行为。

      尝试调用 GC.Collect() 看看这是否能解决您的问题。此外,您需要在发布模式下运行,因为在调试模式下,JIT 会将局部变量的生命周期延长到方法的末尾,即使它们在某个时间点后没有使用。

      【讨论】:

      • 反对票是为了什么?有什么不准确的吗?请报告错误,我会修复!
      【解决方案3】:

      问题的另一方面是您使用什么来确定“内存泄漏”。有许多不同的方法可以测量“空闲”内存,根据不同的方法,您可能会得到完全不同的结果。

      • 任务管理器中显示的内存使用情况 - 由于 GC 使用内存的方式,即使所有内存都被 CLR GC 视为“空闲”,也不太可能下降。
      • GC 内存性能计数器(和属性) - 这些实际上将显示 GC 对内存的看法。您想使用它们来检测托管内存泄漏。

      MemoryStream(以及任何其他大的 86K+)分配还有一件事 - 它们使用只会在完整 GC 时收集的大对象堆,要触发它,您可能需要运行 GC.Collect 两次。在应用程序的正常流程中,这种情况很少发生,因此在应用程序关闭之前您可能看不到此内存被释放。诊断 - 检查 GC 收集性能计数器(GC 数量)。

      还有一点:如果您因为遇到“内存不足”异常而尝试解决内存泄漏,则可能是由地址空间碎片引起的(通常仅适用于 32 位进程)。如果是这种情况 - 考虑创建自己的内存流,它不会在单个块中分配内存,然后在增长流时必须复制它。或者至少尝试在流中预先分配空间。

      【讨论】:

        【解决方案4】:

        我已经使用这种方法进行批处理

            static byte[] buffer;
        
            public static object Read(XmlDocument xmlDocument)
            {
                if (buffer == null)
                {
                    buffer = new byte[1024 * 1024 * 512];
                }
        
                if (xmlDocument != null)
                {
                    using (MemoryStream ms = new MemoryStream(buffer))
                    {
                        xmlDocument.Save(ms);
                        ms.Flush();
                        ms.Seek(0, SeekOrigin.Begin);
        
                        object  result = ReadFromStream(ms);
        
                        ms.Close();
                        return result;
                    }
                }
                else
                {
                    return null;
                }
            }
        

        【讨论】:

          【解决方案5】:

          调用 GC.Collect() 不是一个好的做法,不应该用作解决方案。

          您可以尝试看看这是否会改变任何东西,但不要依赖有意的 GC.Collect() 调用...

          【讨论】:

            猜你喜欢
            • 2011-06-28
            • 2021-07-15
            • 1970-01-01
            • 2015-06-14
            • 2017-02-19
            • 2013-03-08
            • 2021-09-05
            • 2013-03-29
            • 2010-11-28
            相关资源
            最近更新 更多