我有以下代码:

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

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

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

我有一个同行评审坚持要求我手动关闭它,但我找不到信息来判断他的观点是否有效。

有帮助吗?

解决方案

如果某些东西是Disposable,你应该总是处理它。您应该在bar()方法中使用using语句以确保ms2获得Disposed。

它最终会被垃圾收集器清理干净,但Dispose始终是一个好习惯。如果您在代码上运行FxCop,它会将其标记为警告。

其他提示

至少在当前的实施中,你不会泄漏任何东西。

调用Dispose不会更快地清理MemoryStream使用的内存。它阻止您的流在呼叫后对读/写呼叫可行,这可能对您有用,也可能没有用。

如果您完全确定从不想要从MemoryStream转移到另一种流,那么不会对不调用Dispose造成任何伤害。但是,这通常是一种很好的做法,部分原因是如果您更改以使用不同的Stream,您不希望被难以发现的错误所困扰,因为您选择了早期的简单方法上。 (另一方面,有YAGNI论点......)

无论如何,这样做的另一个原因是新的实现可能引入将在Dispose上释放的资源。

是的 a 泄漏,具体取决于您如何定义LEAK以及您的意思是多少......

如果泄漏,则表示“内存仍然已分配,无法使用,即使您已完成使用”而后者你的意思是在调用dispose之后的任何时候,然后是的,可能存在泄漏,尽管它不是永久性的(即在应用程序运行时的生命周期中)。

要释放MemoryStream使用的托管内存,需要取消引用它,通过取消对它的引用,使其立即符合垃圾回收的条件。如果你没有这样做,那么你从使用它之后就会创建一个临时泄漏,直到你的引用超出范围,因为在此期间内存将无法分配。

using语句(简单地调用dispose)的好处是你可以在using语句中声明你的引用。当using语句结束时,不仅要调用dispose,而且你的引用超出了范围,有效地使引用无效并使你的对象立即有资格进行垃圾收集,而不需要你记得写下“reference = null”。代码。

虽然没有立即引用某些内容但不是经典的“永久性”内容。内存泄漏,它肯定有同样的效果。例如,如果您保留对MemoryStream的引用(即使在调用dispose之后),并且在您的方法中稍微向下,则尝试分配更多内存...仍由您引用的内存流使用的内存将不可用直到你取消引用或它超出范围,即使你调用dispose并使用它完成。

这已经得到了回答,但我只想补充一点,信息隐藏的老式原则意味着你可能在未来的某些时候想要重构:

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

为:

Stream foo()
{    
   ...
}

这强调调用者不应该关心返回什么类型的Stream,并且可以更改内部实现(例如,在模拟单元测试时)。

如果您未在条形实现中使用Dispose,则需要遇到麻烦:

void bar()
{    
    using (Stream s = foo())
    {
        // do stuff with s
        return;
    }
}

所有流都实现了IDisposable。在一个using语句中包装你的内存流,你会很好,花花公子。使用块将确保您的流无论如何都会被关闭和处理。

无论你在哪里调用Foo,你都可以使用(MemoryStream ms = foo()),我认为你应该还可以。

不需要调用 .Dispose()(或使用使用包装)。

您调用 .Dispose()的原因是尽快释放资源

考虑一下Stack Overflow服务器,我们有一组有限的内存和数千个请求。我们不想等待计划的垃圾收集,我们希望尽快释放该内存所以它可用于新的传入请求。

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

您可能泄漏内存的唯一情况是您不小心留下对流的引用而从未关闭它。你仍然没有真正泄露内存,但你 不必要地延长你声称使用它的时间。

我建议将 MemoryStream 包装在 bar() 在一个 using 声明主要是为了一致性:

  • 现在 MemoryStream 不释放内存 .Dispose(), ,但有可能在将来的某个时候它可能会发生,或者您(或您公司的其他人)可能会用您自己的自定义 MemoryStream 替换它,等等。
  • 它有助于在您的项目中建立一个模式,以确保 全部 流被处置——通过说“所有流必须被处置”而不是“某些流必须被处置,但某些流不必被处置”来更明确地划定界限......
  • 如果您更改了代码以允许返回其他类型的 Stream,则无论如何您都需要更改它以进行处置。

我通常在类似情况下做的另一件事 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;
}

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

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

现在,对于你的特定问题,不,你不会泄漏记忆。

我不是.net专家,但也许这里的问题是资源,即文件句柄,而不是内存。我想垃圾收集器最终将释放流,并关闭句柄,但我认为最好是明确关闭它,以确保将内容清除到磁盘。

在垃圾收集语言中处理非托管资源是不确定的。即使您明确地调用Dispose,您也无法控制何时实际释放后备内存。当对象超出范围时,无论是通过退出using语句,还是从下级方法弹出callstack,都会隐式调用Dispose。总而言之,有时该对象实际上可能是托管资源(例如文件)的包装器。这就是为什么在finally语句中显式关闭或使用using语句的好习惯。 干杯

MemorySteram只是一个字节数组,它是一个托管对象。 忘记处理或关闭这个没有副作用,除了最终确定之外 只需在反射器中检查MemoryStream的constuctor或flush方法,就可以清楚为什么你不需要担心关闭或处理它,只是为了遵循良好的做法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top