122

私は次のコードを持っています:

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

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

私が割り当てたMemoryStreamがどういうわけか後で破棄されない可能性はありますか?

手動でこれを閉じるように主張するピアレビューがありますが、彼が有効なポイントを持っているかどうかを判断するための情報が見つかりません。

4

12 に答える 12

179

少なくとも現在の実装では、何もリークしません。

Dispose を呼び出しても、MemoryStream が使用するメモリはそれ以上速くクリーンアップされません。呼び出し後にストリームが読み取り/書き込み呼び出しで実行できなくなります。これは、役立つ場合とそうでない場合があります。

絶対に MemoryStream から別の種類のストリームに移動したくない場合は、Dispose を呼び出さなくても害はありませんただし、別のストリームを使用するように変更した場合、早い段階で簡単な方法を選択したため、見つけにくいバグに悩まされたくないという理由もあります(一方で、YAGNI の議論もある...)

とにかくそれを行うもう1つの理由は、新しい実装がDisposeで解放されるリソースを導入する可能性があることです。

于 2008-10-24T16:28:15.987 に答える
64

何かが使い捨ての場合は、常に廃棄する必要があります。Disposedを確実に取得するusingには、メソッドでステートメントを使用する必要があります。bar()ms2

最終的にはガベージ コレクターによってクリーンアップされますが、常に Dispose を呼び出すことをお勧めします。コードで FxCop を実行すると、警告としてフラグが立てられます。

于 2008-10-24T15:42:46.750 に答える
30

はい leakの定義方法と LATER の意味によっては、leak があります...

リークとは、「メモリは割り当てられたままで、使用が終わっても使用できない」ことを意味し、後者は dispose を呼び出した後のいつでも意味する場合、永続的ではありませんが、リークがある可能性があります (つまり、アプリケーションのランタイムの寿命)。

MemoryStream で使用されているマネージ メモリを解放するには、参照を無効にすることで参照を解除する必要があります。これにより、すぐにガベージ コレクションの対象になります。これを行わないと、使用が終わってから参照が範囲外になるまで、一時的なリークが発生します。その間、メモリは割り当てに使用できないためです。

using ステートメントの利点は (単純に dispose を呼び出すよりも)、using ステートメントで参照を DECLARE できることです。using ステートメントが終了すると、dispose が呼び出されるだけでなく、参照がスコープ外になり、実質的に参照が無効になり、オブジェクトがすぐにガベージ コレクションの対象になります。"reference=null" コードを書くことを覚えておく必要はありません。

何かをすぐに参照解除しないことは、従来の「永続的な」メモリ リークではありませんが、間違いなく同じ効果があります。たとえば、(dispose を呼び出した後でも) MemoryStream への参照を保持し、メソッドの少し下の方でより多くのメモリを割り当てようとすると、まだ参照されているメモリ ストリームで使用中のメモリは使用できなくなります。 dispose を呼び出して使用が終わったとしても、参照を無効にするか範囲外になるまで、あなたに。

于 2010-05-14T20:33:03.983 に答える
8

呼び出す.Dispose()(または でラップするUsing) 必要はありません。

呼び出す理由は、できるだけ早くリソース.Dispose()を解放するためです。

たとえば、限られたメモリ セットと数千のリクエストが入ってくるスタック オーバーフロー サーバーについて考えてみましょう。スケジュールされたガベージ コレクションを待つのではなく、できるだけ早くそのメモリを解放して利用できるようにしたいと考えています。新しい受信リクエスト用。

于 2008-10-24T15:45:15.683 に答える
5

すべてのストリームは IDisposable を実装しています。メモリ ストリームを using ステートメントでラップすると、問題なくダンディになります。using ブロックは、何があってもストリームが閉じられ、破棄されることを保証します。

Foo を呼び出す場所はどこでも using(MemoryStream ms = foo()) を実行できますが、それでも問題ないと思います。

于 2008-10-24T15:42:02.523 に答える
3

主に一貫性を保つために、MemoryStream をステートメントでラップすることをお勧めbar()usingます。

  • 現在、MemoryStream は のメモリを解放しません.Dispose()が、将来のある時点で解放されるか、またはあなた (またはあなたの会社の他の誰か) がそれを独自のカスタム MemoryStream に置き換える可能性があります。
  • プロジェクトでパターンを確立して、すべてのストリームが確実に破棄されるようにすることが役立ちます。「一部のストリームは破棄する必要がありますが、特定のストリームは破棄する必要はありません」ではなく、「すべてのストリームを破棄する必要があります」と言うと、よりしっかりと線が引かれます。 ...
  • 他のタイプのストリームを返すことができるようにコードを変更した場合は、とにかく破棄するようにコードを変更する必要があります。

foo()IDisposable を作成して返すときのような場合に私が通常行うもう 1 つのことは、オブジェクトの構築と の間の失敗が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;
}
于 2008-11-23T08:35:16.520 に答える
2

メモリ リークは発生しませんが、ストリームを閉じる必要があるというコード レビュアーの指摘は正しいです。そうするのは礼儀正しい。

メモリ リークが発生する可能性がある唯一の状況は、誤ってストリームへの参照を残し、決して閉じない場合です。実際にメモリをリークしているわけではありませんが、メモリ使用していると主張する時間を不必要に延長しています。

于 2008-10-24T16:22:23.333 に答える
1

オブジェクトが IDisposable を実装している場合は、完了したら .Dispose メソッドを呼び出す必要があります。

一部のオブジェクトでは、Dispose は Close と同じ意味であり、その逆も同様です。その場合、どちらでも良いです。

さて、あなたの特定の質問については、いいえ、メモリリークはありません。

于 2008-10-24T15:42:23.960 に答える
-1

私は .net の専門家ではありませんが、おそらくここでの問題はリソース、つまりファイル ハンドルであり、メモリではありません。ガベージ コレクターは最終的にストリームを解放し、ハンドルを閉じると思いますが、コンテンツを確実にディスクにフラッシュするために、明示的に閉じることが常にベスト プラクティスだと思います。

于 2008-10-24T15:44:37.120 に答える
-2

ガベージコレクションされた言語では、管理されていないリソースの廃棄は決定論的ではありません。Disposeを明示的に呼び出したとしても、バッキングメモリが実際に解放されるタイミングを完全に制御することはできません。オブジェクトがスコープ外になると、usingステートメントを終了するか、従属メソッドからコールスタックをポップアップするかどうかに関係なく、Disposeが暗黙的に呼び出されます。これはすべて言われていますが、オブジェクトが実際には管理対象リソース(ファイルなど)のラッパーである場合もあります。これが、finallyステートメントを明示的に閉じるか、usingステートメントを使用することをお勧めする理由です。乾杯

于 2009-05-15T15:58:41.397 に答える
-3

MemorySteram は管理対象オブジェクトである byte の配列に他なりません。これを破棄または閉じるのを忘れても、ファイナライズのオーバーヘッド以外の副作用はありません。
リフレクターで MemoryStream のコンストラクターまたはフラッシュ メソッドを確認するだけで、グッド プラクティスに従う以外に、それを閉じたり破棄したりすることを心配する必要がない理由が明らかになります。

于 2013-01-08T08:51:19.960 に答える