Я понимаю, что делает System.WeakReference, но то, что я не могу понять, является практическим примером того, чем он может быть полезен. Сам класс, похоже, мне нравится. Мне кажется, что есть другие, более эффективные способы решения проблемы, где WeakReference используется в примерах, которые я видел. Каков канонический пример того, где вы действительно должны использовать WeakReference? Разве мы не пытаемся получить дальше в стороне от этого типа поведения и использования этого класса?Практическое использование System.WeakReference
ответ
Один полезный пример ребята, которые управляют db4o объектно-ориентированную базу данных. Там WeakReferences используются как своего рода световой кеш: он будет хранить ваши объекты в памяти только до тех пор, пока ваше приложение будет работать, что позволит вам поставить настоящий кеш сверху.
Другое применение было бы в реализации слабых обработчиков событий. В настоящее время один большой источник утечек памяти в .NET-приложениях забывает удалить обработчики событий. Например.
public MyForm()
{
MyApplication.Foo += someHandler;
}
Уточнить возникшую проблему? В приведенном выше фрагменте MyForm будет храниться в памяти навсегда, пока MyApplication жив в памяти. Создайте 10 MyForms, закройте их все, ваши 10 MyForms по-прежнему будут в памяти, сохранены в памяти обработчиком событий.
Введите WeakReference. Вы можете создать слабый обработчик событий с помощью WeakReferences, чтобы someHandler был слабым обработчиком событий MyApplication.Foo, тем самым устраняя утечки памяти!
Это не просто теория. Дастин Кэмпбелл из блога DidItWith.NET опубликовал an implementation of weak event handlers с использованием 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;
}
/* ... */
}
Я использую слабую ссылку для сохранения состояния в mixins. Помните, mixins являются статическими, поэтому, когда вы используете статический объект для присоединения состояния к нестационарному, вы никогда не знаете, сколько времени потребуется. Поэтому вместо хранения Dictionary<myobject, myvalue>
я сохраняю Dictionary<WeakReference,myvalue>
, чтобы предотвратить смешение микшинга слишком долго.
Единственная проблема в том, что каждый раз, когда я делаю доступ, я также проверяю мертвые ссылки и удаляю их. Не то, чтобы они причиняли кому-либо боль, если, конечно, не было тысяч.
Есть две причины, по которым вы бы использовали WeakReference
.
Вместо глобальных объектов, объявленных как статические: глобальные объекты объявлены как статические поля и статические поля не могут быть GC'ed (сборки мусора) до
AppDomain
является GC'ed. Таким образом, вы рискуете исключениями вне памяти. Вместо этого мы можем обернуть глобальный объект вWeakReference
. Несмотря на то, что самWeakReference
объявлен статическим, объект, на который он указывает, будет GC'ed, когда память будет низкой.В принципе, используйте
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'ed в самом конце, даже после того, какThingsWrapper
есть - то есть, когда GC'edAppDomain
является GC'ed.Thing() staticThing Thing() privateThing ~Thing() privateThing ~ThingsWrapper ~Thing() staticThing
Вместо этого мы можем обернуть
Thing
вWeakReference
. ПосколькуwrStaticThing
может быть GC'ed, нам понадобится ленивый метод, который я забыл для краткости.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'ed, когда АЯ нить вызываются.Thing() wrStaticThing ~Thing() wrStaticThing ~WeakReferenceThing WeakReference is dead.
Для объектов, которые требуют много времени для инициализации: Вы не хотите объектов, которые по времени consusming Инициализировать быть GC'ed. Вы можете либо сохранить статическую ссылку, чтобы избежать этого (с минусами из выше точки), либо использовать
WeakReference
.
+1 для наконечника с обработчиком событий, thats awesome !!!! – 2009-03-24 21:49:22