【翻譯】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.

  因此,對於弱引用的最好的建議是:概要描述或者用基準問題測試它,以確保你爲特定的環境選擇最好的方案。

相關文章
相關標籤/搜索