문제

나는 무엇을 이해한다 시스템.약한 참조 하지만 내가 이해할 수 없는 것은 그것이 유용할 수 있는 실제적인 예입니다.제가 보기엔 수업 자체가 해킹인 것 같습니다.내가 본 예에서 WeakReference가 사용되는 문제를 해결하는 다른 더 나은 방법이 있는 것 같습니다.WeakReference를 실제로 사용해야 하는 표준적인 예는 무엇입니까?우리는 얻으려고 노력하고 있지 않습니까? 더 멀리 이런 유형의 행동과 이 클래스의 사용에서 벗어나시겠습니까?

도움이 되었습니까?

해결책

한 가지 유용한 예는 DB4O 객체 지향 데이터베이스를 실행하는 사람들입니다.WeakReferences는 일종의 라이트 캐시로 사용됩니다.응용 프로그램이 작동하는 동안에만 개체를 ​​메모리에 유지하므로 실제 캐시를 맨 위에 놓을 수 있습니다.

또 다른 용도는 약한 이벤트 핸들러를 구현하는 것입니다.현재 .NET 애플리케이션에서 메모리 누수의 가장 큰 원인 중 하나는 이벤트 핸들러를 제거하는 것을 잊는 것입니다.예:

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

문제가 보이나요?위의 코드 조각에서 MyForm은 MyApplication이 메모리에 살아있는 한 영원히 메모리에 유지됩니다.10개의 MyForm을 생성하고 모두 닫으면 10개의 MyForm이 여전히 메모리에 남아 있으며 이벤트 핸들러에 의해 활성 상태로 유지됩니다.

WeakReference를 입력합니다.WeakReferences를 사용하여 약한 이벤트 핸들러를 구축하면 someHandler가 MyApplication.Foo에 대한 약한 이벤트 핸들러가 되어 메모리 누수 문제를 해결할 수 있습니다!

이것은 단순한 이론이 아닙니다.DidItWith.NET 블로그의 Dustin Campbell 게시 약한 이벤트 핸들러 구현 System.WeakReference를 사용합니다.

다른 팁

나는 이를 사용하여 사용되지 않은 항목이 자동으로 가비지 수집되는 캐시를 구현합니다.

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

    /* ... */
   }

저는 믹스인의 상태 유지를 위해 약한 참조를 사용합니다.믹스인은 정적이므로 정적 개체를 사용하여 상태를 비정적 개체에 연결하는 경우 얼마나 오래 걸릴지 알 수 없습니다.그래서 보관하는 대신 Dictionary<myobject, myvalue> 나는 Dictionary<WeakReference,myvalue> 믹스인이 너무 오랫동안 드래그하는 것을 방지합니다.

유일한 문제는 액세스할 때마다 죽은 참조도 확인하고 제거한다는 것입니다.물론 수천 명이 아닌 이상 누구에게도 해를 끼치는 것은 아닙니다.

사용하는 이유는 두 가지입니다. WeakReference.

  1. 정적으로 선언된 전역 객체 대신:전역 개체는 정적 필드로 선언되며 정적 필드는 AppDomain GC되었습니다.따라서 메모리 부족 예외가 발생할 위험이 있습니다.대신에 전역 객체를 다음과 같이 래핑할 수 있습니다. WeakReference.비록 WeakReference 자체가 정적으로 선언되면 메모리가 부족할 때 가리키는 개체가 GC됩니다.

    기본적으로 사용 wrStaticObject 대신에 staticObject.

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

    AppDomain이 있을 때 정적 개체가 가비지 수집되었음을 증명하는 간단한 앱입니다.

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

    아래 출력에서 ​​참고하세요. staticThing 이후에도 맨 마지막에 GC됩니다. ThingsWrapper 이다 - 즉GC된 경우 AppDomain GC되었습니다.

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

    대신 우리는 포장할 수 있습니다 Thing 안에 WeakReference.처럼 wrStaticThing GC가 가능하다면 간결성을 위해 생략한 지연 로드 메서드가 필요합니다.

    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
    }
    

    아래 출력에서 ​​참고하세요. wrStaticThing GC 스레드가 호출되면 GC됩니다.

    Thing() wrStaticThing
    ~Thing() wrStaticThing
    ~WeakReferenceThing
    WeakReference is dead.
    
  2. 초기화하는 데 시간이 많이 걸리는 객체의 경우:초기화하는 데 시간이 많이 걸리는 객체가 GC되는 것을 원하지 않습니다.이를 방지하기 위해 정적 참조를 유지하거나(위의 단점이 있음) 다음을 사용할 수 있습니다. WeakReference.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top