Вместо глобальных объектов, объявленных как статические : Глобальные объекты объявляются как статические поля, и статические поля не могут быть обработаны GC (сборщик мусора) до тех пор, пока AppDomain
не будет GC. Таким образом, вы рискуете исключения из памяти. Вместо этого мы можем обернуть глобальный объект в 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'ed, когда AppDomain
- GC'ed.
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-потоке.
Thing() wrStaticThing
~Thing() wrStaticThing
~WeakReferenceThing
WeakReference is dead.