天天看點

4種Java引用淺解

最近研究java cache實作,發現使用到了軟引用(softreference),不太了解,查閱了jdk文檔、代碼以及幾篇文章。做個小結,如有錯誤,歡迎指正。

之是以想學習一下java的幾種引用類型,原因有兩個:

了解java cache實作、學習java引用與java垃圾回收機制的關系

記憶體資源是有限的,需要合理的利用。cache不是僅僅hashmap那麼簡單,java引用與java垃圾回收機制也有非常緊密的關系。

避免對java引用的錯誤使用

某個同僚把5000+交易資料放到一個hashmap裡面,用一個spring singleton bean的全局屬性指向該hashmap。大量運用這種技術,很快就報out of memory。再大的記憶體也架不住對記憶體的錯誤使用。了解原理有助于我們盡量少犯或不犯低級錯誤。

當java虛拟機(jvm)覺得記憶體不夠用的時候,會觸發垃圾回收操作(gc),清除無用的對象,釋放記憶體。可是如何判斷一個對象是否是垃圾呢?其中的一個方法是計算指向該對象的引用數量,如果引用數量為0,那麼該對象就為垃圾(thread對象是例外),否則還有用處,不能被回收。但是如果把引用數為0的對象都回收了,還是不能滿足記憶體需求怎麼辦?java把引用分為4種類型,垃圾回收器會嘗試回收隻有弱引用的對象。

按照一個對象的引用可達(reachable)強度,由強到弱分為5類,如下:

強可達(strong reachable)

在一個線程内,無需引用直接可達,新建立的對象是強可達的。

軟可達(soft reachable)

不是強可達的,但是通過一個軟引用(softreference)可達。

弱可達(soft reachable)

既不是強可達也不是軟可達,但是通過一個弱引用(weakreference)可達。

虛可達(phantom reachable)

既不是強可達,不是軟可達,也不是弱可達,但是通過一個虛引用(phantomreference)可達。

不可達(unreachable)

沒有任何引用指向對象。

比較好、容易了解的是java垃圾回收器會優先清理可達強度低的對象。另外有兩個重要的點:

強可達的一定不會被清理

jvm保證抛出out of memory之前,清理所有的軟引用對象

在實作一個緩存系統的時候,如果全部使用強引用,那麼你需要自己去手動的把某些引用clear掉(引用置位null),否則遲早會抛出out of memory錯誤。緩存系統引入弱引用或者軟引用的唯一原因是,把引用clear的事情交由java垃圾回收器來處理,cache程式自己置身事外。

幾種弱引用的使用方式非常相近。下面分别介紹4種引用類型。

我們平時申明變量使用的就是強引用,普通系統99%以上都是強引用。比如,<code>string s = "hello world"</code>

垃圾回收器某個時刻決定回收軟可達的對象的時候,會清理軟引用,并可選的把引用存放到一個引用隊列(referencequeue)。

類似弱引用,隻不過java虛拟機會盡量讓軟引用的存活時間長一些,迫不得已才清理。

僅用來處理資源的清理問題,比object裡面的finalize機制更靈活。get方法傳回的永遠是null,java虛拟機不負責清理虛引用,但是它會把虛引用放到引用隊列裡面。

使用hashmap,會報out of memory錯誤。

使用weakhashmap,不會報out of memory錯誤。

java語言裡面數組(array)、清單(list)、map等容器,對裡面的每一個對象都有一個引用,大資料的情況下要小心記憶體洩露。弱引用隻适合cache等特殊場景,對于那些一定不能java讓垃圾回收器回收的對象,要使用強引用。

jdk java.lang.ref封包檔,以及類說明