2008-08-19 10 views
33

System.WeakReferenceのことを理解していますが、私が把握できないようなことは、それが役に立つかもしれない実用的な例です。クラスそのものは、まあ、ハックだと思われます。私が見た例でWeakReferenceが使われている問題を解決するための、より良い手段が他にもあるようです。 WeakReferenceを実際に使用しなければならない場所の正式な例は何ですか? から遠ざけようとしていないのですか?System.WeakReferenceの実際の使用

答えて

44

一つの有用な例としては、db4oのオブジェクト指向データベースを実行する男です。そこでは、WeakReferenceは一種のライトキャッシュとして使用されます。アプリケーションが実行している間だけオブジェクトをメモリに保持し、実際のキャッシュを上に置くことができます。

また、弱いイベントハンドラの実装にも使用されます。現在、.NETアプリケーションでのメモリリークの大きな原因の1つは、イベントハンドラを削除することを忘れることです。例えば。

public MyForm() 
{ 
    MyApplication.Foo += someHandler; 
} 

を参照してください。上記のスニペットでは、MyApplicationがメモリ内に存続している限り、MyFormは永久にメモリに保持されます。 10個のMyFormを作成し、それらをすべて閉じると、あなたの10個のMyFormsはまだメモリに残っており、イベントハンドラによって保持されます。

WeakReferenceを入力してください。 WeakReferencesを使用してweakイベントハンドラを構築し、someHandlerがMyApplication.Fooの弱いイベントハンドラであるため、メモリリークを修正できます。

これは単なる理論ではありません。 DidItWith.NETのブログのDustin Campbellは、an implementation of weak event handlersという掲示板をSystem.WeakReferenceで掲示しました。

+3

+1、素晴らしいthatsの!!!! –

+0

ええ、それはかなり気の利いたものです。他のタイプのEventHandler(非ジェネリックなEventHandler、PropertyChangedEventHandlerなど)を扱うために、ここでコードを採用しました。それは私たちのために非常にうまくいきました。 –

12

私は未使用のエントリが自動的にガベージコレクトされているキャッシュを実装するためにそれを使用します。

class Cache<TKey,TValue> : IEnumerable<KeyValuePair<TKey,TValue>> 
{ Dictionary<TKey,WeakReference> dict = new Dictionary<TKey,WeakReference>(); 

    public TValue this[TKey key] 
    { get {lock(dict){ return getInternal(key);}} 
     set {lock(dict){ setInteral(key,value);}}  
    } 

    void setInteral(TKey key, TValue val) 
    { if (dict.ContainsKey(key)) dict[key].Target = val; 
     else dict.Add(key,new WeakReference(val)); 
    } 


    public void Clear() { dict.Clear(); } 

    /// <summary>Removes any dead weak references</summary> 
    /// <returns>The number of cleaned-up weak references</returns> 
    public int CleanUp() 
    { List<TKey> toRemove = new List<TKey>(dict.Count); 
     foreach(KeyValuePair<TKey,WeakReference> kv in dict) 
     { if (!kv.Value.IsAlive) toRemove.Add(kv.Key); 
     } 

     foreach (TKey k in toRemove) dict.Remove(k); 
     return toRemove.Count; 
    } 

    public bool Contains(string key) 
    { lock (dict) { return containsInternal(key); } 
    } 

    bool containsInternal(TKey key) 
     { return (dict.ContainsKey(key) && dict[key].IsAlive); 
     } 

    public bool Exists(Predicate<TValue> match) 
     { if (match==null) throw new ArgumentNullException("match"); 

     lock (dict) 
     { foreach (WeakReference weakref in dict.Values) 
      { if ( weakref.IsAlive 
        && match((TValue) weakref.Target)) return true; 
     } 
     } 

     return false; 
    } 

    /* ... */ 
    } 
2

ミックスインでの状態保持に弱いリファレンスを使用しています。ミックスインは静的であることを覚えておいてください。静的オブジェクトを使用して非静的オブジェクトに状態をアタッチする場合、必要な時間は決してわかりません。だから、私はをつけておくのではなく、mixinが長すぎるものをドラッグするのを防ぐためにDictionary<WeakReference,myvalue>を守っています。

唯一の問題は、私がアクセスするたびに、私も死んだ参照をチェックし、それらを削除することです。もちろん、数千人がいなければ、誰もが傷つけるわけではありません。

0

WeakReferenceを使用する理由は2つあります。代わりにグローバルオブジェクトの

  1. 静的として宣言:AppDomainがGC'edれるまで静的フィールドおよび静的フィールドが(ガベージコレクション)をGC'edすることができないなどのグローバルオブジェクトが宣言されています。したがって、メモリ不足例外が発生する可能性があります。代わりに、WeakReferenceにグローバルオブジェクトをラップすることができます。 WeakReference自体は静的であると宣言されていますが、メモリが少ないときは、そのオブジェクトが指し示すオブジェクトはGC'edされます。

    基本的には、staticObjectの代わりにwrStaticObjectを使用しています。

    class ThingsWrapper { 
        //private static object staticObject = new object(); 
        private static WeakReference wrStaticObject 
         = new WeakReference(new object()); 
    } 
    

    AppDomainのときに静的オブジェクトがガベージコレクションされることを証明する簡単なアプリケーション。即ちGC'ed AppDomainがGC'edされたとき - staticThing次の出力から

    class StaticGarbageTest 
    { 
        public static void Main1() 
        { 
         var s = new ThingsWrapper(); 
         s = null; 
         GC.Collect(); 
         GC.WaitForPendingFinalizers(); 
        } 
    } 
    class ThingsWrapper 
    { 
        private static Thing staticThing = new Thing("staticThing"); 
        private Thing privateThing = new Thing("privateThing"); 
        ~ThingsWrapper() 
        { Console.WriteLine("~ThingsWrapper"); } 
    } 
    class Thing 
    { 
        protected string name; 
        public Thing(string name) { 
         this.name = name; 
         Console.WriteLine("Thing() " + name); 
        } 
        public override string ToString() { return name; } 
        ~Thing() { Console.WriteLine("~Thing() " + name); } 
    } 
    

    注非常にThingsWrapperであっても後の終わりにGC'edれます。

    Thing() staticThing 
    Thing() privateThing 
    ~Thing() privateThing 
    ~ThingsWrapper 
    ~Thing() staticThing 
    

    代わりに、私たちはWeakReferenceThingをラップすることができます。 wrStaticThingはGCで処理することができるので、簡潔にするために除外した遅延ロードメソッドが必要です。 GCスレッドが呼び出されたときにそのwrStaticThing以下の出力から

    class WeakReferenceTest 
    { 
        public static void Main1() 
        { 
         var s = new WeakReferenceThing(); 
         s = null; 
         GC.Collect(); 
         GC.WaitForPendingFinalizers(); 
         if (WeakReferenceThing.wrStaticThing.IsAlive) 
          Console.WriteLine("WeakReference: {0}", 
           (Thing)WeakReferenceThing.wrStaticThing.Target); 
         else 
          Console.WriteLine("WeakReference is dead."); 
        } 
    } 
    class WeakReferenceThing 
    { 
        public static WeakReference wrStaticThing; 
        static WeakReferenceThing() 
        { wrStaticThing = new WeakReference(new Thing("wrStaticThing")); } 
        ~WeakReferenceThing() 
        { Console.WriteLine("~WeakReferenceThing"); } 
        //lazy-loaded method to new Thing 
    } 
    

    注GC'edれます。時間のかかるを初期化するために、あるオブジェクトの場合

    Thing() wrStaticThing 
    ~Thing() wrStaticThing 
    ~WeakReferenceThing 
    WeakReference is dead. 
    
  2. :あなたは時間consusmingがGC'edされるinitにあるオブジェクトを望んでいません。あなたはそれを避けるために静的な参照を維持することができます(上記の点を控えて)。WeakReferenceを使用してください。 EventHandlerの持つ先端のための

関連する問題