14

ここの PowerShell に関するドキュメントには、次の興味深いコメントがあります。

PowerShell powershell = PowerShell.Create();

using (powershell)
{
    //...
}

// Even after disposing of the PowerShell object, we still 
// need to set the powershell variable to null so that the 
// garbage collector can clean it up.
powershell = null;

破棄後にpowershell設定する必要があるのはなぜですか?null

4

3 に答える 3

17

これは直接 PowerShell の問題ではありません。usingブロックが終了すると、指定されたオブジェクトのメソッドDispose()が呼び出されます。これらは通常、メモリリークなどを避けるために、いくつかのクリーンアップ操作を行います。ただし、Dispose()オブジェクトは削除しません。オブジェクトへの参照がまだブロックの外に存在する場合using(この例のように)、オブジェクト自体はまだスコープ内にあります。それへの参照がまだあるため、ガベージ コレクションを行うことはできません。したがって、まだメモリを占有しています。

あなたの例で彼らがしているのは、その参照を削除することです。が null に設定されている場合powershell、参照している他の変数がないため、それが指していた PowerShell オブジェクトは孤立しています。ガベージ コレクターがそれを把握すると、メモリを解放できます。いずれにせよ、これはメソッドの最後に発生します (powershell範囲外になるため) が、この方法では、システム リソースを少し早く元に戻すことができます。

(編集: Brian Rasmussen が指摘しているように、.NET ランタイムはガベージ コレクションに関して非常に巧妙です。powershellコード内の最後の参照に到達すると、ランタイムはそれがもう必要ないことを検出し、ガベージ コレクションのために解放する必要があります。したがって、このpowershell = null;行は実際には何もしていません。)

ところで、このパターンは私には非常に奇妙に見えます。通常のアプローチは次のようなものです。

using (PowerShell powershell = PowerShell.Create())
{
   //...
}

このようにして、ブロックが破棄された直後powershellのブロックの最後で範囲外になります。変数がどこに関連しているかが分かりやすくなり、行usingが不要になるためコードを節約できます。すでに処分された状態には決して存在しないpowershell = nullため、これはより良いコーディング方法であるとさえ言えます。powershell誰かがあなたの元のコードを変更しpowershell、ブロックの外で使用しようとするとusing、何が起こってもおそらく悪いことになります.

于 2013-05-15T16:31:47.493 に答える
6

null に設定する必要はありません。.NET ガベージ コレクターは、コードが対応する変数に null 値を割り当てていない場合でも、特定の命令の後にオブジェクトが使用されていないことを検出できます。(詳細については、 http://blogs.msdn.com/b/cbrumme/archive/2003/04/19/51365.aspxを参照してください。)「公式」の例に、誤解を招くようなコメントを含むこの余分なコードが含まれている理由については、ドキュメントでさえ、バグがあります...

于 2013-05-15T17:15:09.093 に答える
1

到達不能である限り、ガベージコレクションの対象である限り、アドバイスは正しくありません。(これを示すコードについては、C#でメモリを解放する正しい方法を参照してください)物事を無効にする唯一の理由は次のとおりです

  • メモリ リークのトラブルシューティングを容易にするため
  • GC が到達不能と判断するのに問題がある可能性のある参照 (パブリック プロパティなど) を削除するには

どちらも、実際にはオブジェクトDisposeメソッド内でのみ実行します

于 2013-05-16T18:38:31.287 に答える