声明:本篇博客翻译自:http://tipsandtricks.runicsoft.com/CSharp/WeakReferences.html
由于水平(技术水平+英语理解能力)有限/不足,肯定会有所疏漏/错误,请及时指正。
在日常开发中,通常会遇到一些大对象的处理。这些大对象通常在整个程序中多次使用。例如:大文件对象,大的字典类。通常情况下我们会使用下面的方式:
作为一个方法的内置本地变量;
作为一个类的字段存在;
这两种方式都不是很好。作为一个类的字段,类的实例将一直持有这个大对象,消耗很多内存;作为一个方法的本地变量使用,当方法执行完毕,这个大对象离开了作用域,但此时不一定会被GC直接回收。造成不必要的内存消耗。且每次调用该方法时,会重新创建新的大对象,增加程序的内存消耗。
如果创建对象很消耗资源,且我们想要避免多次创建同一个对象。可以使用类的字段方式。
通常情况下,当一个对象离开了作用域,或者被设置为null。我们将无法访问到它。.NET提供了一个WeakReference类,可以完美的解决这个问题。
WeakReference对象将保存一个对象的引用即使这个对象已经离开了作用域或者被设置为null了,通过WeakReference还可以访问到这个对象。除非被GC回收掉了,WeakReference对象此时无法访问到该对象。
WeakReference的使用非常简单,
MyHugeObject hugeObject = new MyHugeObject(); WeakReference w = new WeakReference(hugeObject);
通过WeakReference的Target属性可以获得关联的对象,
MyHugeObject = w.Target as MyHugeClass;
如果这个对象仍然存在,通过Target属性可以获得到。如果对象已经被GC回收了,Target得到的值为null
static void Func() { MyHugeClass MyHugeObject; if ( (w == null) || ( (MyHugeObject=w.Target as MyHugeClass) == null) ) { MyHugeObject = new MyHugeClass(); w = new WeakReference(MyHugeObject); } // work with MyHugeObject }
WeakReference提供给我们很大的好处:它将保持MyHugeObject的引用,并且确保可以在没有被GC回收的情况下重新得到该对象,且不用担心重新获得的对象是不完整的或者被损坏的。
PS:使用WeakReference并不能保证提高程序的性能,大多数情况下相比于使用本地局部变量而言性能会有所提高。但是不做任何担保。一些情况下还会出现更多的程序性能消耗,例如一个大对象关联了许多小对象,此时会将这些小对象也转成Weak Reference。此时会对GC内存回收有损耗。
参考链接:
https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/weak-references
http://tipsandtricks.runicsoft.com/CSharp/WeakReferences.html
https://msdn.microsoft.com/en-us/library/system.weakreference(v=vs.110).aspx