弱引用研究


通常、オブジェクトリファレンスといえば、オブジェクトが到達可能な状態(プログラムによってアクセスされる)である限り、ゴミ回収器はそれを回収しないという強いリファレンスを指すのが一般的です.
弱いリファレンスのオブジェクトは不可とされていますが、アプリケーションからアクセスできます.また、ゴミ回収機によって回収されます.ごみ収集をサポートする言語の多くは、Java、C#、Pythonなどの弱い引用をサポートしています.
通常、弱いリファレンスは、メモリを大量に消費するオブジェクトに特に適していますが、ゴミ回収機能で回収すると再作成しやすくなります.C#でWeakReferenceクラスを使用して弱い参照オブジェクトを作成します.
サンプルコードは次のとおりです.
public string FilePath = "PathToMyImportantFile.dat";
       public WeakReference WeakRef = new WeakReference(null);
       public object ImportantBigFileContents
       {
           get
           {
               object bigObject = WeakRef.Target;
               if (bigObject == null)//           ,     null,        。
               {
                   using (StreamReader r = new StreamReader(FilePath))
                       bigObject = r.ReadToEnd();
                   WeakRef.Target = bigObject;
               }
               return bigObject;
           }
       }

ImportantBigFileContentsは、メモリを占有するオブジェクトであるクラスのプロパティであると仮定すると、この大きなオブジェクトを弱いリファレンスで格納することが考えられます.
弱い参照のTargetプロパティの値がまだ存在する場合は、この値を直接取得して返します.この値がゴミ回収器で回収された場合、この値はnullです.そのため、大きなオブジェクトを再構築する必要があります.
ゴミ回収器がいつ起動するかは、プログラマーがコントロールできないため、弱い参照オブジェクトがいつ回収されるかは確定できません.したがって、次のコードのようなエラーを犯しやすいです.
public object ImportantBigFileContents
       {
           get
           {
               if (WeakRef.Target == null)
                   using (StreamReader r = new StreamReader(FilePath))
                       WeakRef.Target = r.ReadToEnd();
               return WeakRef.Target;
           }
       }

何も間違っていないように見えます.Target属性がnullの場合は大きなオブジェクトが構築する、WeakRefの場合は.Targetに値がある場合は、その値を返します.
しかし、ここには小さな確率のことがあります.ゴミ回収器は非同期で実行されているので、いつ回収するか分かりません.return WeakRefを呼び出す可能性があります.Target;文の前に回収しました.そうするとnullが返されます.したがって、弱いリファレンスオブジェクトを読み込む前に、強いリファレンスオブジェクトに入れるか、つまり普通のオブジェクトに入れるかが推奨されます.
弱いリファレンスは、メモリ漏洩のリスクを処理するためにも使用できます.例えば、一般的なゴミ回収アルゴリズムはリファレンスカウントであり、リファレンスカウント法はオブジェクトがリファレンスされた回数を計算し、リファレンスされた回数が0の場合、そのオブジェクトを回収します.ただし、リングリファレンスのオブジェクトは回収できません.すなわち、例えばAのオブジェクトがBオブジェクトを参照し、BのオブジェクトもAオブジェクトを参照している場合、ゴミ回収器はAオブジェクトとBオブジェクトを回収することができず、このようなリング参照が多くなるとメモリリークを引き起こす.
AオブジェクトとBオブジェクトを弱引用にすると、GCは必要なときにリソースを回収します.
ただし、ポインタ自体がオブジェクトと同じ大きさであるか、オブジェクトよりも大きい可能性があるため、小さなオブジェクトに弱い参照を使用することは避けます.実際、メモリがそれほど緊張していなければ、弱いリファレンスを過度に使用する必要はありません.