如果.NET中的MemoryStream未closures,是否会产生内存泄漏?

我有以下代码:

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

有没有机会,我已经分配的MemoryStream将以某种方式不能被丢弃?

我有一个同行评审坚持我手动closures这个,我找不到信息来判断他是否有一个有效的点。

如果某件事是一次性的,你应该总是处置它。 你应该在你的bar()方法中使用using语句来确保ms2被取消。

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

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

调用Dispose不会更快地清理MemoryStream使用的内存。 在通话之后, 它将阻止您的信息stream对于读/写通话可行,这对您可能有用或不可用。

如果你完全确定你永远不想从MemoryStream移动到另一种types的stream,那么对于不调用Dispose不会有任何伤害。 但是,这通常是一个好的做法,部分原因是因为如果你改变了使用不同的Stream,你不想被一个难以发现的错误所困扰,因为你早期select了简单的方法。 (另一方面,有YAGNI的说法…)

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

是的,有一个泄漏 ,这取决于你如何定义泄漏和多less你后来的意思是…

如果通过泄漏,你的意思是“内存仍然分配,即使你已经完成了使用,也不能使用”。后者是指在调用dispose之后的任何时候,然后是可能会有泄漏,虽然它不是永久性的应用程序运行时的生命周期)。

为了释放MemoryStream使用的托pipe内存, 您需要将其取消引用 ,通过取消对引用的引用,以便它立即可以进行垃圾回收。 如果你不这样做,那么你创build一个临时的泄漏,直到你的引用超出了范围,因为在这期间内存将不能被分配。

使用语句的好处(通过简单地调用dispose)是,您可以在using语句中声明您的引用。 当使用语句结束时,不仅可以调用dispose,而且可以引用超出范围,从而有效地取消引用并使对象立即符合垃圾回收的条件,而不要求您记住写入“reference = null”代码。

虽然没有马上解决这个问题并不是一个经典的“永久性”的内存泄漏,但它确实具有相同的效果。 例如,如果您保留对MemoryStream的引用(即使在调用dispose之后),并且在方法中更深入一点,也可以尝试分配更多的内存…由您仍然引用的内存stream使用的内存将不可用直到你取消了引用,或者它超出了范围,即使你调用了dispose并且使用了它。

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

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

至:

 Stream foo() { ... } 

这强调了调用者不应该关心返回什么types的Stream,并且可以改变内部实现(例如,当嘲笑unit testing时)。

如果你没有在你的bar实现中使用Dispose,那么你将会遇到麻烦:

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

所有的stream都实现IDisposable。 用using语句包装你的Memorystream,你会很好,很好看。 使用块将确保您的stream是closures和处置无论如何。

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

调用.Dispose() (或Using包装”)不是必需的。

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

比如说Stack Overflow服务器,我们有一组有限的内存和数千个请求。我们不想等待计划的垃圾收集,我们希望尽快释放内存,以便可用为新的传入的请求。

你不会泄漏内存,但你的代码审查是正确的,表明你应该closures你的stream。 这样做很有礼貌

您可能会泄漏内存的唯一情况是您不小心留下了对stream的引用,并且从不closures它。 你仍然没有真正的内存泄漏,但是你不必要地延长了你声称使用它的时间。

我build议在using语句的bar()中包装MemoryStream,主要是为了保持一致性:

  • 现在MemoryStream不会释放.Dispose()上的内存,但是有可能在将来的某个时刻,或者你(或者你公司的其他人)可能用你自己定制的MemoryStream代替它。
  • 这有助于在你的项目中build立一个模式,以确保所有的 Streams被处置 – 通过说“所有的Streams必须被处理”而不是“一些Streams必须被处理,但是某些不必处理” …
  • 如果您更改了代码以允许返回其他types的Stream,则需要将其更改为无论如何处置。

在创build和返回一个IDisposable时,我通常在做例如foo()时做的另一件事是确保构造对象和return之间的任何失败都被exception捕获,处理对象并抛出exception:

 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专家,但也许这里的问题是资源,即文件句柄,而不是内存。 我猜垃圾收集器最终会释放这个stream,然后closures这个句柄,但是我认为最好的做法是明确地closures它,以确保将内容清空到磁盘。

垃圾收集语言中非托pipe资源的处理是非确定性的。 即使您明确调用Dispose,也完全无法控制后备内存何时被释放。 当对象超出范围时,Dispose被隐式调用,无论是通过退出using语句,还是从下级方法popup调用堆栈。 这一切被说,有时对象可能实际上是托pipe资源(例如文件)的包装。 这就是为什么在最后的语句中显式closures或使用using语句是很好的做法。 干杯

MemorySteram不过是字节数组,它是被pipe理的对象。 忘记处理或closures这个没有任何副作用,除了头顶定案。
只需在reflection器中检查构造器或者刷新MemoryStream的方法,就可以清楚地知道为什么你不必担心closures或者处理它,而不仅仅是为了跟随好的练习。