代码之家  ›  专栏  ›  技术社区  ›  Coderer

如果.NET中的MemoryStream未关闭,是否会造成内存泄漏?

  •  102
  • Coderer  · 技术社区  · 16 年前

    我有以下代码:

    MemoryStream foo(){
        MemoryStream ms = new MemoryStream();
        // write stuff to ms
        return ms;
    }
    
    void bar(){
        MemoryStream ms2 = foo();
        // do stuff with ms2
        return;
    }
    

    我分配的MemoryStream是否有可能在以后无法处理?

    我有一个同行评议坚持要我手动关闭这个,但我找不到信息来判断他是否有正确的观点。

    12 回复  |  直到 16 年前
        1
  •  179
  •   Jon Skeet    16 年前

    至少在当前的实现中,您不会泄漏任何信息。

    调用Dispose不会更快地清理MemoryStream使用的内存。信息技术 停止流在调用后执行读/写调用,这可能对您有用,也可能对您不有用。

    从不 如果您想从MemoryStream移动到另一种流,不调用Dispose不会对您造成任何伤害。然而,这通常是一种好的做法,部分原因是如果你 更改为使用不同的流,您不想被难以找到的bug咬到,因为您在早期选择了简单的方法。(另一方面,有雅格尼论点…)

    也许

        2
  •  64
  •   Deantwo    5 年前

    using 你的声明 bar() 确定方法 ms2

        3
  •  29
  •   Icemanind    9 年前

    ,这取决于您如何定义泄漏,以及您所指的延迟时间。。。

    如果泄漏的意思是“内存仍然被分配,不可使用,即使您已经使用完毕”,而后者的意思是在调用dispose之后的任何时间,那么可能存在泄漏,尽管它不是永久性的(即在应用程序运行时的生命周期内)。

    你需要取消引用它 ,使您对它的引用无效,这样它就可以立即进行垃圾收集。如果您没有做到这一点,那么您将创建一个临时泄漏,从您使用它的时候开始,直到您的引用超出范围,因为在此期间内存将无法分配。

    虽然无法立即取消引用某些内容并不是经典的“永久性”内存泄漏,但它肯定具有相同的效果。例如,如果您保留对MemoryStream的引用(即使在调用dispose之后),并且在方法中再往下一点,您将尝试分配更多内存。。。即使调用了dispose并使用完毕,但在取消引用或引用超出范围之前,仍被引用的内存流所使用的内存将不可用。

        4
  •  9
  •   to StackOverflow    15 年前

    这已经得到了回答,但我只想补充一点,信息隐藏的传统原则意味着您可能在将来某个时候想要重构:

    MemoryStream foo()
    {    
        MemoryStream ms = new MemoryStream();    
        // write stuff to ms    
        return ms;
    }
    

    致:

    Stream foo()
    {    
       ...
    }
    

    如果您没有在bar实现中使用Dispose,那么您将需要遇到麻烦:

    void bar()
    {    
        using (Stream s = foo())
        {
            // do stuff with s
            return;
        }
    }
    
        5
  •  8
  •   Jeff Atwood    16 年前

    使命感 .Dispose() Using

    你打电话的原因是什么 .Dispose() 尽快释放资源 .

    以堆栈溢出服务器(Stack Overflow server)为例,在该服务器中,我们有一组有限的内存和数千个请求。我们不希望等待计划的垃圾收集,我们希望尽快释放内存,以便新的传入请求可以使用它。

        6
  •  5
  •   Nick    16 年前

    无论您在哪里调用Foo,都可以使用(MemoryStream ms=Foo())进行操作,我认为您应该仍然可以。

        7
  •  3
  •   Chris R. Donnelly    16 年前

    我建议将MemoryStream包装成 bar() 在一个 using 声明主要用于一致性:

    • .Dispose() ,但也有可能在将来的某个时候,您(或您公司的其他人)可能会用您自己的定制MemoryStream来替换它,等等。
    • 它有助于在项目中建立一种模式,以确保 流被处理——更明确的界线是说“所有流都必须被处理”,而不是“某些流必须被处理,但某些流不必”。。。
    • 如果您曾经更改代码以允许返回其他类型的流,那么无论如何都需要将其更改为dispose。

    foo() 创建和返回IDisposable时,要确保在构造对象和 return 被异常捕获、处置对象并重新引发异常:

    MemoryStream x = new MemoryStream();
    try
    {
        // ... other code goes here ...
        return x;
    }
    catch
    {
        // "other code" failed, dispose the stream before throwing out the Exception
        x.Dispose();
        throw;
    }
    
        8
  •  2
  •   OwenP    16 年前

    您不会泄漏内存,但您的代码审阅者指示您应该关闭流是正确的。这样做是有礼貌的。

    唯一可能泄漏内存的情况是,您意外地留下了对流的引用,并且从未关闭它。您仍然没有真正泄漏内存,但是

        9
  •  1
  •   Lasse V. Karlsen    16 年前

    如果对象实现了IDisposable,则必须在完成后调用.Dispose方法。

    在某些对象中,Dispose与Close的含义相同,反之亦然,在这种情况下,两者都是好的。

        10
  •  -1
  •   Steve    16 年前

        11
  •  -2
  •   Rob Daigneau Rob Daigneau    15 年前

        12
  •  -3
  •   user1957438    12 年前

    MemorySteram只是字节数组,它是托管对象。 忘记处理或关闭,这并没有任何副作用,除了在头上完成。
    只需检查反射器中内存流的构造或冲洗方法,就可以清楚地知道,除了遵循良好实践之外,您不必担心关闭或处理它的原因。