1. 程式人生 > >Java中的引用型別(強引用、弱引用)和垃圾回收

Java中的引用型別(強引用、弱引用)和垃圾回收

Java中的引用型別和垃圾回收

強引用Strong References

  強引用是最常見的引用:

  比如:

StringBuffer buffer = new StringBuffer();

  建立了一個StringBuffer類的物件,並用一個變數buffer儲存對這個物件的引用。這就是個強引用。

  變數持有的是這個物件的引用。通常,引用是一個物件的儲存地址。

  Java不像C或者C++一樣,Java沒有取地址符號&,也沒有解引用符號*或者->。

  引用不同於指標,引用不能與整形進行互相轉換,也不能進行增減操作。

  強引用是和垃圾回收機制相關的。

  一般的,如果一個物件可以通過一系列的強引用引用到,那麼就說明它是不會被垃圾回收機制(Garbage Collection)回收的。

  因為垃圾回收是不會回收你正在使用的物件的。

垃圾回收機制Garbage Collection

  如果一個物件,沒有一個引用指向它,那麼它就被認為是一個垃圾。

  An object is considered garbage when there are no longer any references to it stored in any variables, the fields of any objects, or the elements of any arrays.

  在某一個時間,garbage collector將會發現成為垃圾的物件,然後回收它所佔用的記憶體。

  C中用malloc()和free()來管理記憶體。

  C++是用new和delete來分配和管理記憶體空間。

  而Java使用garbage collection機制,不用程式設計師寫程式碼管理,這樣會有一些效能上的影響,因為garbage collector會主動地回收記憶體。

  但是,GC機制減少了記憶體洩露,並且提高了程式設計師的效率。

什麼時候強引用會太強了?

  有時候應用會使用一些不能被繼承的類,比如一個final的類,或者一個工廠方法返回的介面,並不知道有多少具體實現。

  而我們想給這個類增加一個欄位,比如給每一個物件一個序列號,於是我們用了HashMap,把這個類的物件作為key,一個序列號作為value。

  這時候我們就必須100%確定地知道一個特定物件的序列號什麼時候不再需要(比如物件的生命週期已經結束,就不再需要它的序列號屬性),這樣我們就可以從map中移除它的entry。

  如果我們在應當移除引用的時候沒有移除,垃圾回收將一直不會回收這個物件,引起記憶體洩露。

  而如果我們過早地移除了我們還在使用的物件的引用,又會發現自己丟失了資訊。

  這些都是C/C++程式設計師經常會遇到的問題。而我們用的是Java,我們還要考慮這些,豈不是鬧複雜了?

  強引用另一個常見的問題是快取問題。

  比方說,影象的快取。影象快取應當阻止我們重複載入影象。

  所以影象快取儲存有記憶體中已有的所有影象的引用,如果使用通常的強引用,強引用本身會使得影象一直存留在記憶體中,這樣就使得程式設計師像上面一樣,必須自己決定什麼時候移除快取中的引用,這樣物件才能被垃圾回收機制回收。

  這樣你就又放棄了讓GC自己管理垃圾回收的機制,而開始手動地管理記憶體。

引用物件類

  Java的引用物件類在包java.lang.ref下。

  其中包含了三種顯式的引用型別(也即是Reference類的三個子類):

  SoftReference

  WeakReference

  PhantomReference

  一個引用物件(reference object)(即以上三種引用型別的物件)封裝了一個對其他物件的引用(稱作referent)。

  引用物件提供了對referent的clean和get操作,但是不提供set操作。

  引用物件本身可以像其他一般的物件一樣被檢查和操縱。

  三種類型的引用定義了三種不同層次的可達性級別,由強到弱排列如下:

  SoftReference > WeakReference > PhantomReference

  越弱表示對垃圾回收器的限制越少,物件越容易被回收。

SoftReference

  SoftReference用來實現一些記憶體敏感的快取(Soft references are for implementing memory-sensitive caches),只要記憶體空間足夠,物件就會保持不被回收。

  反之,當宿主程序的記憶體空間不足時,物件就會被GC回收。

  所以SoftReference意味著:hold on until you can’t.

WeakReference

  WeakReference可以用來實現一些規範化對映(WeakHashMap),其中key或者value當它們不再被引用時可以自動被回收。

  當你想引用一個物件,但是這個物件有自己的生命週期,你不想介入這個物件的生命週期,這時候你就是用弱引用。

  這個引用不會在物件的垃圾回收判斷中產生任何附加的影響。

PlantomReference

  PlantomReference和WeakReference一樣,也不會介入引用物件的生命週期。

  PhantomReference用來排程一些預驗清理動作,提供比Java清理機制更靈活的處理方式。(Phantom references are for scheduling pre-mortem cleanup actions in a more flexible way than is possible with the Java finalization mechanism.)

  PlantomReference比較特殊,它的get方法總是返回null,所以你得不到它引用的物件。

  它儲存ReferenceQueue中的軌跡。

  它允許你知道物件何時從記憶體中移除。