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下。

  http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html#package_description

 

  其中包含了三種顯式的引用類型(也即是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中的軌跡。

  它允許你知道對象何時從內存中移除。

 

 

參考資料:

  Java官方文檔描述:

  http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html

  Android官方文檔:

  http://developer.android.com/reference/java/lang/ref/Reference.html

 

  Stackoverflow上的討論:

  http://stackoverflow.com/questions/3329691/understanding-javas-reference-classes-softreference-weakreference-and-phanto

 

  博文:

  https://weblogs.java.net/blog/enicholas/archive/2006/05/understanding_w.html

  http://java.dzone.com/articles/reference-types-java-part-1

  http://zhang-xzhi-xjtu.iteye.com/blog/413159

  http://blog.yohanliyanage.com/2010/10/ktjs-3-soft-weak-phantom-references/

 

  書籍:

  《Java in a nutshell》

  http://docstore.mik.ua/orelly/java-ent/jnut/ch02_10.htm

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM