.net的弱引用是什么?弱引用看起來很神奇,似乎是凌駕于正常的垃圾回收機制之上的,它究竟是如何實現的呢?其實WeakReference類型在內部封裝了一個名為GCHandle的struct類型,正是這個GCHandle使弱引用成為可能。下面西安達內科技(www.xatarena.cn)培訓講師就詳細為大家介紹。
CLR中的每個AppDomain都擁有一個GC句柄表。這個表的每一項記錄有兩個信息,一個是指向堆中某個對象的指針,另一個是這個表項的類型。總共有4種表項類型,其中Weak和WeakTrackResurrection兩種類型和我們今天所討論的弱引用相關。GCHandle這個類提供了一些操縱GC句柄表的方法。我們可以使用它的Alloc方法向GC句柄表中添加一個指定類型的表項。當垃圾回收開始后,垃圾回收器找到所有可達對象(簡單的說,就是有用的對象)。然后遍歷GC句柄表中每個Weak類型的表項,如果發現某表項所指的對象不屬于可達對象,則會把該表項的對象指針設置為null。緊接著,垃圾回收器會找出所有不可達對象中定義了析構函數的對象,并把他們放到一個被稱為freachable的隊列中(freachable中的對象會等待一個CLR中特定的線程來調用他們的終結函數)。由于這些freachable中的對象現在又被freachable隊列所引用,所以它們又成為可達對象了。此時,垃圾回收器會遍歷GC句柄表中所有WeakTrackResurrection類型的表項,和剛才一樣,如果某表項所指的對象不屬于可達對象,則會把該表項的對象指針設置為null。此處需注意,對于那些一開始被判定為不可達且定義了析構函數的對象來說,它們在GC句柄表中所對于的表項指針仍然不是null。這就是Weak和WeakTrackResurrection兩種類型的區別。
WeakReference就是通過表示了某個GC句柄表表項的GCHandle對象來完成跟蹤對象生命周期的功能的。你也一定可以看出短弱引用利用了Weak類型的GC句柄表項,而長弱引用則利用了WeakTrackResurrection類型的表項。
WeakReference的一些注意事項
首先,WeakReference自身也實現了析構函數。也就是說,它即使不再被使用了,也不會被立即回收,而是會在內存里賴著多活一會(可能會經歷不止一次的垃圾回收)。
另外,如上一節所說,WeakReference會向GC句柄表添加一個表項。而每次垃圾回收,GC句柄表都會被遍歷一遍。可想而知,如果系統中存在大量的WeakReference,那么GC句柄表很可能也會非常龐大,導致垃圾回收的效率降低。 |
 |
|