【问题标题】:C# BinaryWriter Memory Leak [duplicate]C# BinaryWriter 内存泄漏
【发布时间】:2018-04-24 14:43:31
【问题描述】:

我最近一直在使用 DotSpatial 库,并注意到我的程序内存泄漏非常严重。我一直在使用 VS 内存诊断工具,并设法将问题缩小到以下(简化)代码块:

using (var inMemoryStream = new MemoryStream())
using (var _writer = new BinaryWriter(inMemoryStream))
{
    WriteHeader(_writer);
   _writer.Close();
}

BinaryWriter 对象维护对 inMemoryStream 对象的引用,分配给它的 OutStream 属性。似乎无论使用何种处置方法(使用/关闭/处置),此内存流都不会释放它为其缓冲区分配的内存。

我已经设法通过创建一个继承自 BinaryWriter 的类、覆盖 Close() 并将“OutStream = null”添加到该方法来解决这个问题,但这似乎很笨拙。

我错过了什么吗? BinaryWriter 不应该完全处理传递给它的流吗?似乎 BinaryWriter.Close() 确实尝试对此做一些事情,因为使用智能感知查看 OutStream 的某些属性会显示 ObjectDisposed 异常。我正在使用 .NET 4.5.2,如果这有影响的话。

提前多谢指教

【问题讨论】:

  • MemoryStream 在其实现中只是一个原生字节数组。当两者都在using 块的末尾超出范围时,它们都将不再有任何引用,并将被垃圾收集器清理。你确定内存泄漏不是来自WriteHeader(_writer)吗?
  • 想想你的假设。为什么作者要处理作为参考传递给它的流?如果作者不知道的其他对象也持有对流的引用怎么办?

标签: c# .net memory-leaks binaryreader


【解决方案1】:

您似乎认为Dispose 的意思是“清理引用”。有时可能会出现这种情况,但Dispose 的实际目的是释放非托管资源。虽然有很多滥用 Dispose 用于其他目的(感谢方便的 using 语法等),但您不应该期待更多。

关闭文件正在释放非托管资源。关闭数据库连接正在释放非托管资源。摆脱对另一个托管对象的引用?为什么你会期望这会作为Dispose 的一部分发生?你在丢弃引用之前调用Dispose - 无论如何你不能再重复使用它,你不能以任何方式使用已处置的对象。

当然,在某些情况下这会导致内存泄漏。但在这种情况下,内存泄漏总是存在 - Dispose 只能使其更小。现在这当然是值得的——但解决方案仍然是解决问题并释放引用,而不是试图找到减少泄漏资源量的方法。

【讨论】:

    【解决方案2】:

    Dispose 不会释放托管内存。这就是垃圾收集器的工作。因此,虽然仍然可以从程序范围(即从所有静态变量或当前本地变量)访问 MemoryStream 的引用,但不会释放内存。

    即使 MemoryStream 不再被引用,它也完全取决于 GC 何时释放内存。它不一定是立即的,甚至是不久之后。这取决于其他因素,例如整体内存压力。

    【讨论】:

    • 我认为值得一提的是,可以使用System.GC.Collect 强制立即进行垃圾收集。 msdn.microsoft.com/en-us/library/…
    • @JuanR 好点。我还要补充一点,可能很少有场景是必要的,甚至是有益的,而且让 GC 完成它的工作几乎总是更好。除非您正在编写类似游戏的东西,而您不能让 GC 在不适当的时间运行。
    • 同意 100%!...如果要以这种方式强制收集,您需要完全了解自己在做什么。
    猜你喜欢
    • 2016-01-27
    • 2010-11-11
    • 2017-02-18
    • 1970-01-01
    • 2015-11-19
    • 2014-11-01
    • 2020-03-31
    • 2016-03-15
    • 2015-07-25
    相关资源
    最近更新 更多