【翻译】C# Tips & Tricks: Weak References - When and How to Use Them

原文:C# Tips & Tricks: Weak References - When and How to Use Themhtml

Sometimes you have an object which is very large and needed multiple times, but not constantly, throughout your application. For example a huge lookup table, or the contents of a large file you need in memory for some algorithm. To work with this object, you traditionally have two options:
- As a local variable inside the method that needs it
- As a field in a class that lives during the whole time the object could be needed算法

  有时候,你有一个很大的对象,屡次但又不常常须要它,且遍及整个应用。好比一个庞大的查找表或者一个大文件的内容存于内存中用于一些算法。传统地,要使用这个对象,你有两种选择:数据结构

  • 做为一个局部变量内置于须要它的方法中
  • 做为一个字段存在于一个类中,存活于须要该对象的整个时间周期中

Both solutions aren't optimal if your object is very huge, and only sometimes needed:app

  若是你的对象十分大,而且只有有些时候须要,那么以上两种方法都不是最理想的:ide

The class field solution keeps the object in memory the whole time, giving your application a huge permanent memory footprint increase. And the local variable solution will decrease application performance, since the object not only has to be created anew every time it's needed, but also deleted each time it goes out of scope, generating work for the Garbage Collector.性能

  类字段的方案整个时间周期保持对象于内存中,形成内存持久占用。局部变量方案会下降应用的性能,由于不只要在每次须要它的时候被从新建立,并且在每次超出做用域的时候删除它,给垃圾回收增长了工做量。测试

If the creation of the object is very expensive, and you want to avoid doing it multiple times, the class field solution is your way to go. But in all cases where the object is a cheap-to-create memory hog, a better solution than both of the above would be welcome.this

  若是建立这个对象代价很是高,你想避免屡次这样操做,类字段的方法是你会采用的。可是当这个对象能够被廉价建立,一种较之于以上两种方案更好的方案将会更受欢迎。
Luckily for us, .Net 4.0 gives us a middle-ground solution in the form of weak references.spa

  幸运的是,.Net 4.0以弱引用的形式给了咱们一个折衷的方案。code

Usually, when an object goes out of scope, or is set to null, it is no longer accessible to us, even if the garbage collector will only delete the object much later.

  一般,当一个对象超出做用域或者被置空,对于咱们它将再也不能被访问,尽管垃圾回收会在好久之后删除这个对象。

A weak reference object will keep a reference to an object that went out of scope or was set to null, until it is actually deleted by the garbage collector. But until that happens, we can get the object back!

  一个弱引用对象将会保持一个指向一个超出做用域或者被置空的对象的引用,直到它确实被垃圾回收删除。直到被删除前,咱们一直能够把该对象取回来。

So our new option to work with a large object is to use a weak reference to it. The weak reference itself should become a long-living class member. And in the method that needs our huge object, we check if the weak reference holds an object, which we will use if it does. And if not, we create a new instance.

  因而咱们对于一个较大对象的选择是使用一个弱引用指向它。这个弱引用自己将成为一个长期存活的类成员。在须要咱们的大对象的方法中,咱们检查这个弱引用是否持有一个对象,若是是则咱们将会使用它。若是不是,咱们建立一个新实例。

This way, when we first run our method, a new instance of the huge object is created. But when we run it the next time, and the garbage collector hasn't deleted the object in the meantime, we can reuse it, and don't need to create a new instance.

  这样,当咱们第一次运行咱们的方法的时候,这个大对象的一个新实例会被建立。但当咱们下次运行它时,与此同时垃圾回收尚未删除找个对象,咱们能够重用它,而不须要建立一个新的实例。

The actual usage is pretty simple.

  实际用法很简单。

To create a weak reference to an object, we simply call the constructor with the object:

  为了建立一个指向一个对象的弱引用,咱们简单的的调用这个构造器并传入这个对象:

1 WeakReference w = new WeakReference(MyHugeObject);

To get the underlying object from a weak reference, we use its .Target property:

  为了从一个弱引用中获得这个对象,咱们使用 its.Target 属性:

1 MyHugeObject = w.Target as MyHugeClass;

If the object still exists, it is returned. If it was claimed by the garbage collector, a null refence is returned by the 'as' operator.

  若是这个对象一直存在,他会被返回。若是被垃圾回收了,会经过 'as' 操做符返回一个空引用。

So, given that we have a WeakReference w as a field in our class, we would use it inside the method that does something with a HugeObject like this:

  因而,在咱们的类中有一个 WeakReference 类型的变量 w 做为一个字段,咱们将在这个方法里使用它结合一个 HugeObject 来作一些事情,像这样:

 1 static void Func()
 2 {
 3     MyHugeClass MyHugeObject;            
 4     if ( (w == null) || ( (MyHugeObject=w.Target as MyHugeClass) == null) )
 5     {
 6         MyHugeObject = new MyHugeClass();
 7         w = new WeakReference(MyHugeObject);
 8     }
 9     // work with MyHugeObject             
10 }

First we declare the MyHugeObject variable, which will be initialized to null by the compiler. Then we check if our weak refence is null (which is the case when Func runs for the very first time) or if the assignment from w.Target returned null. If either is the case, we (re)create MyHugeObject and assign it to w, after which we can then do some work with MyHugeObject.

  首先咱们声明了这个 MyHugeObject 类型的变量,将会被编译器初始化为 null 。而后咱们检查咱们的弱引用是否为空(就是在 Func 第一次运行的状况)或者 w.Target 为空。若是知足任何一种状况,咱们建立 MyHugeObject 并把它赋值给 w,以后,咱们能够用 MyHugeObject 来作些事情。

Now, WeakReference does us one huge favor: it takes care of all members of MyHugeObject, and makes sure we only get it back if all its members are still intact, so we don't need to worry that we get back an incomplete object.

  如今,WeakReference 带给咱们一个好处:它负责 MyHugeObject 的全部成员,并确保只有在它全部成员完好无损的状况下咱们才能取回它,所以咱们不须要担忧取回一个不完整的对象。

A drawback is that WeakReference doesn't play well with objects that implement IDisposable, since we cannot call Dispose() (or have it called automatically through the 'using' statement) through a WeakRefence to the object.

  WeakReference 的一个缺点是不能很好地和实现 IDisposable 接口的对象协做,是由于咱们不能经过一个指向该对象的 WeakRefence 来调用 Dispose()(或者经过 'using' 语句自动使它被调用)。

And finally a word of warning: weak references aren't a guaranteed profit for application performance. In most cases, they will make an algorithm more performant than when using very large local variables. But it's not guaranteed, and in some cases it could produce noticeable overhead (for example when the huge object is a data structure consisting of many smaller objects with references to each other, and a WeakRefence to the data structure turns all those internal refernces to weak references, this might incur garbage collector overhead, because every reference has to be checked to decide if the object as a whole can be recovered or deleted).

  最后一个警告:弱引用不能保证为应用的性能带来好处。在大多数状况下,它们会使算法更高性能的,较之于使用一个大局部变量。但这并不能被保证,且在有些状况下会引发明显的开销(好比,当这个大对象是一个由许多较小的之间互相引用的对象构成的数据结构,一个 WeakRefence 指向这个数据结构会把全部的内部引用转变成弱引用,这可能会引发垃圾回收器的开销,由于每个引用必须被检查来肯定是否这个对象能够被恢复或者被删除)。

So the best advice with weak references is: profile or benchmark it, to make sure that you choose the best solution for your specific situation.

  因此,对于弱引用的最好的建议是:概要描述或者用基准问题测试它,以确保你为特定的环境选择最好的方案。

相关文章
相关标签/搜索