Practical use of System.WeakReference

后端 未结 4 1391
鱼传尺愫
鱼传尺愫 2021-01-30 21:35

I understand what System.WeakReference does, but what I can\'t seem to grasp is a practical example of what it might be useful for. The class itself seems to me to be, well, a h

4条回答
  •  傲寒
    傲寒 (楼主)
    2021-01-30 21:51

    There are two reasons why you would use WeakReference.

    1. Instead of global objects declared as static: Global objects are declared as static fields and static fields cannot be GC'ed (garbage-collected) until the AppDomain is GC'ed. So you risk out-of-memory exceptions. Instead, we can wrap the global object in a WeakReference. Even though the WeakReference itself is declared static, the object it points to will be GC'ed when memory is low.

      Basically, use wrStaticObject instead of staticObject.

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

      Simple app to prove that static object is garbage-collected when AppDomain is.

      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); }
      }
      

      Note from the output below staticThing is GC'ed at the very end even after ThingsWrapper is - i.e. GC'ed when AppDomain is GC'ed.

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

      Instead we can wrap Thing in a WeakReference. As wrStaticThing can be GC'ed, we'll need a lazy-loaded method which I've left out for brevity.

      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
      }
      

      Note from output below that wrStaticThing is GC'ed when GC thread is invoked.

      Thing() wrStaticThing
      ~Thing() wrStaticThing
      ~WeakReferenceThing
      WeakReference is dead.
      
    2. For objects that are time-consuming to initialize: You do not want objects that are time-consusming to init to be GC'ed. You can either keep a static reference to avoid that (with cons from above point) or use WeakReference.

提交回复
热议问题