私は次のコードを持っています:
MemoryStream foo(){
MemoryStream ms = new MemoryStream();
// write stuff to ms
return ms;
}
void bar(){
MemoryStream ms2 = foo();
// do stuff with ms2
return;
}
私が割り当てたMemoryStreamが後で何らかの方法で破棄されない可能性はありますか?
これを手動で閉じると主張するピアレビューがありますが、彼が有効なポイントを持っているかどうかを知るための情報を見つけることができません。
何かが使い捨ての場合は、常に廃棄する必要があります。 bar()
メソッドでusing
ステートメントを使用して、ms2
は破棄されます。
最終的にはガベージコレクターによってクリーンアップされますが、Disposeを呼び出すことは常に良い習慣です。コードでFxCopを実行すると、警告としてフラグが立てられます。
少なくとも現在の実装では、何もリークしません。
Disposeを呼び出しても、MemoryStreamが使用するメモリはより速くクリーンアップされません。それwill呼び出し後の読み取り/書き込み呼び出しに対してストリームが実行可能になるのを停止します。
neverがMemoryStreamから別の種類のストリームに移動することを絶対に確信している場合、Disposeを呼び出さないことは害になりません。ただし、doを変更して別のストリームを使用する場合は、簡単な方法を早期に選択したため、見つけにくいバグに噛まれたくないため、一般的には良い習慣です。に。 (一方で、YAGNIの議論があります...)
とにかくそれを行うもう1つの理由は、新しい実装mayがDisposeで解放されるリソースを導入することです。
はい、aリーク、LEAKの定義方法と後の意味に応じて...
リークによって「メモリは割り当てられたままで、使用し終わっても使用できない」ことを意味し、後者によってdisposeを呼び出した後はいつでも意味する場合は、永続的ではないがアプリケーションランタイムの寿命)。
MemoryStreamで使用されているマネージメモリを解放するには、参照を解除する必要があります、参照を無効にして、すぐにガベージコレクションの対象となります。これを行わないと、使用中にメモリが割り当てに使用できなくなるため、使用が終了してから参照がスコープから外れるまで一時的なリークが発生します。
(単純にdisposeを呼び出すよりも)usingステートメントの利点は、usingステートメントで参照を宣言できることです。 usingステートメントが終了すると、disposeが呼び出されるだけでなく、参照がスコープ外になり、参照を事実上無効にして、「reference = null」コードを記述することを忘れずにオブジェクトをガベージコレクションに適格にします。
すぐに何かを参照解除しないと、古典的な「永続的な」メモリリークではありませんが、間違いなく同じ効果があります。たとえば、(disposeを呼び出した後でも)MemoryStreamへの参照を保持し、メソッドの少し下にさらにメモリを割り当てようとすると、まだ参照されているメモリストリームで使用されているメモリが使用できなくなります。破棄を呼び出して使用し終わったとしても、参照を無効にするか範囲外になるまで、.
これはすでに答えられていますが、情報隠蔽の古き良き原則により、将来的にはリファクタリングが必要になる可能性があることを付け加えます。
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ステートメントでメモリストリームをラップすると、元気になります。 usingブロックは、ストリームが何であれ閉じられ、破棄されることを保証します。
fooを呼び出す場所ならどこでも(MemoryStream ms = foo())を使用して行うことができ、それでも大丈夫だと思います。
.Dispose()
(またはUsing
でラップ)を呼び出す必要はありません。
.Dispose()
を呼び出す理由は、できるだけ早くリソースを解放するです。
たとえば、スタックオーバーフローサーバーについて考えてみましょう。このサーバーでは、メモリのセットが限られており、数千のリクエストが着信します。新しい着信要求の場合。
主に一貫性を保つために、using
ステートメントのbar()
でMemoryStreamをラップすることをお勧めします。
.Dispose()
のメモリを解放しませんが、将来のある時点で、またはあなた(またはあなたの会社の誰か)が独自のカスタムMemoryStreamで置き換える可能性がありますなど.IDisposableを作成して返すときにfoo()
のような場合に私が通常行うもう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;
}
メモリをリークすることはありませんが、コードレビューアーは、ストリームを閉じる必要があることを示しています。そうするのは礼儀正しいことです。
メモリをリークする可能性がある唯一の状況は、誤ってストリームへの参照を残し、決して閉じない場合です。あなたはまだ実際にメモリをリークしていませんが、あなたはそれを使用していると主張する時間を不必要に延長しますare.
オブジェクトがIDisposableを実装する場合、完了したら.Disposeメソッドを呼び出す必要があります。
一部のオブジェクトでは、DisposeはCloseと同じことを意味し、その逆も同様です。その場合、どちらかが適切です。
さて、あなたの特定の質問に対して、いいえ、あなたはメモリをリークしません。