Java对象的引用类型
轉(zhuǎn)載自?Java對象的引用類型
Java對象的引用類型有強引用,軟引用,弱引用,虛引用和FinalReference,提供這幾種引用類型的主要目的:
1.程序員可以通過不同的引用方式?jīng)Q定某些對象的生命周期;
2.利用JVM的垃圾回收機制,對象可達性分析,進行不同策略的垃圾回收;
3.合理的利用軟,弱,虛引用可以避免內(nèi)存溢出等風險。
? ? ?下面來詳細談?wù)勥@幾種類型引用,首先需要了解一下對象的可達性,java對象不同生命周期,可達性的狀態(tài)也是不一樣,具體分為強可達,軟可達,和弱可達,幻象可達和不可達(不可達基本上可以直接回收了),這些可達性狀態(tài)基本上對應(yīng)著對象引用的類型關(guān)系 ,jvm依賴對象可達性來進行垃圾回收的。
?
1.強引用
創(chuàng)建一個對象并把這個對象賦給一個引用變量
Object?object?=?new?Object(); String?str?=?"hello";? ? ?強引用有引用變量指向時永遠不會被垃圾回收,JVM寧愿拋出OutOfMemory錯誤也不會回收這種對象。如果想中斷強引用和某個對象之間的關(guān)聯(lián),可以顯示地將引用賦值為null,這樣一來的話,JVM在合適的時間就會回收該對象。
2.引用
?????說一下Reference引用對象是后面提到的軟,弱,虛,Final的基類,所以后面的幾個引用類型都是基于它來擴展的,如果需要使用最好配合帶ReferenceQueue的構(gòu)造函數(shù)進行使用,Reference基于ReferenceQueue進行垃圾回收的。帶queue的構(gòu)造引用,垃圾回收過程中,該對象會經(jīng)歷Active->Pending(等待GC)->Enqueued(入隊)->Inactive(完全回收)的狀態(tài),這個對象放到隊列里的作用就是當我們使用引用的時候,可以查詢這個隊列,來判斷對象內(nèi)存是否被回收。具體可以看一下源碼。下面就介紹具體的子類引用類型。
3.軟引用
??????如果一個對象具有軟引用,內(nèi)存空間足夠,垃圾回收器就不會回收它;如果內(nèi)存空間不足了,才會被GC。只要垃圾回收器沒有回收它,該對象就可以被程序使用。
3.1 簡單使用
public?class?SoftReferenceTest?{public?static?void?main(String[]?args)?{SoftReference?softReference?=?new?SoftReference(new?String("object"));String?softObject?=?(String)?softReference.get();} }?
3.2 軟引用的特點
? ? ?SoftReference的特點,在垃圾線程對這個Java對象回收前,SoftReference類所提供的get()方法返回Java對象的強引用。另外,一旦垃圾線程回收該Java對象之 后,get()方法將返回null。Java虛擬機的垃圾收集線程對軟可及對象和其他一般Java對象進行了區(qū)別對待,軟可及對象的清理是由垃圾收集線程根據(jù)其特定算法按照內(nèi)存需求決定的。
具體策略:垃圾收集線程會在虛擬機拋出OutOfMemoryError之前回收軟可及對象,而且虛擬機會盡可能優(yōu)先回收長時間閑置不用的軟可及對象,對那些剛剛構(gòu)建的或剛剛使用過的“新”軟可反對象會被虛擬機盡可能保留。
3.3 配合ReferenceQueue
? ? ? 作為一個Java對象,SoftReference對象除了具有保存軟引用的特殊性之外,也具有Java對象的一般性。所以,當軟可及對象被回收之后,雖然這個SoftReference對象的get()方法返回null,但這個SoftReference對象已經(jīng)不再具有存在的價值,需要一個適當?shù)那宄龣C制,避免大量SoftReference對象帶來的內(nèi)存泄漏。在java.lang.ref包里還提供了ReferenceQueue。當這個SoftReference所軟引用的對象被垃圾收集器回收的同時,ref所強引用的SoftReference對象被列入ReferenceQueue。也就是說,ReferenceQueue中保存的對象是Reference對象,而且是已經(jīng)失去了它所軟引用的對象的Reference對象。在任何時候,我們都可以調(diào)用ReferenceQueue的poll()方法來檢查是否有它所關(guān)心的非強可及對象被回收。利用這個方法,我們可以檢查SoftReference軟引用對象是否被回收。
@Test public?void?testRefQueue()?{ReferenceQueue?queue?=?new?ReferenceQueue();//創(chuàng)建一個軟引用new?SoftReference(new?String("xxx"),?queue);/***?GC后進行一次手動check,并清除*/SoftReference?remove?=?null;while?((remove?=?(SoftReference)?queue.poll())?!=?null)?{//?清除refSystem.out.println("SoftReference?不為?null,這里進行手動清除");remove.clear();} }?
3.4 為什么需要使用軟引用?
? ? ?在我們平時開發(fā)當中,如果我們希望對象盡可能的存在時間長一點,在內(nèi)存允許的情況下,一些可緩沖的對象就可以使用軟引用的方式進行持有對象,或者在一段時間內(nèi),該對象使用的頻次比較多,過了熱點時間,就不會被使用,這樣我們可以大大減少沒必要的對象再次創(chuàng)建,就像使用緩存一樣。所以軟引用可用來實現(xiàn)內(nèi)存敏感的高速緩存,使用軟引用能防止內(nèi)存泄露,增強程序的健壯性。軟引用和弱引用都可以解決OOM問題。
例如:軟引用的一個使用例子,維護一個用戶緩存
?
4. 弱引用
4.1 弱引用的特點
? ? ?弱引用WeakReference也是用來描述非必需對象的,當JVM進行垃圾回收時,無論內(nèi)存是否充足,都會回收被弱引用關(guān)聯(lián)的對象。弱引用也可以用來操作敏感緩存的對象,配合jvm的自身GC機制,來實現(xiàn)自動回收內(nèi)存的效果,同樣WeakReference也可以和引用隊列一起使用。
?public?static?void?main(String[]?args)?{WeakReference<String>?reference?=?new?WeakReference<String>(new?String("zzzz"));System.out.println(reference.get());//通知GVM回收資源System.gc();System.out.println(reference.get());}? ? ? 執(zhí)行結(jié)果:第二個輸出結(jié)果是null,這說明只要JVM進行垃圾回收,被弱引用關(guān)聯(lián)的對象必定會被回收掉。不過要注意的是,這里所說的被弱引用關(guān)聯(lián)的對象是指只有弱引用與之關(guān)聯(lián),如果存在強引用同時與之關(guān)聯(lián),則進行垃圾回收時也不會回收該對象(軟引用也是如此)。
例如這樣寫:
這樣兩次System.out都會輸出“zzzz”
?
4.2 為什么使用弱引用?
? ? ? 一個長生命周期的對象如果對一個短生命周期的持有引用,那么這個短什么周期的對象一直無法被GC,這是出現(xiàn)內(nèi)存泄露的一個原因,所以為了避免這種情況,我們可以運用WeakReference來持有該對象的引用,這樣就不會出現(xiàn)長生命周期的對象的持有導致內(nèi)存溢出。比如HashMap持有很對Object對象,其中有短周期的對象可以替換成虛引用。WeakHashMap就是運WeakReference實現(xiàn)的,從它entry子類中可以看出,它的key是WeakReference包裹住的。當這個key對象本身不再被使用時,伴隨著GC的發(fā)生,會自動把該key對應(yīng)的entry都在Map中清除掉。
?
5. 虛引用
5.1 虛引用的特點
? ? ? 虛引用(PhantomReference)和前面的軟引用、弱引用不同,它并不影響對象的生命周期。如果一個對象與虛引用關(guān)聯(lián),phantomReference.get()都是null,則跟沒有引用與之關(guān)聯(lián)一樣,在任何時候都可能被垃圾回收器回收。
5.2 虛引用的作用
? ? ? PhantomReference主要作為其指向的referent被回收時的一種通知機制,它就是利用上文講到的ReferenceQueue實現(xiàn)的。當referent被gc回收時,可以通過這個通知機制來做額外的清場工作。因此有些情況可以用PhantomReference 代替finalize(),做資源釋放更明智。
public?static?void?main(String[]?args)?{ReferenceQueue<String>?queue?=?new?ReferenceQueue<String>();PhantomReference<String>?pr?=?new?PhantomReference<String>(new?String("hello"),?queue);System.out.println(pr.get());}?
6. FinalReference
? ? ? FinalReference 引用類型主要是為虛擬機提供的,提供對象被gc前需要執(zhí)行finalize方法的對象 的機制。只是把訪問權(quán)限改為package,因此我們是無法直接使用,jVM會對那些實現(xiàn)了Object中finalize()方法的類實例化一個對應(yīng)的FinalReference,關(guān)于具體的細節(jié)有興趣大家可以去看一下Finalizer的源碼;
,其中包括Finalizer對象初始化守護線程,jvm注冊Finalizer對象(實例化FinalReference),GC后入ReferenceQueue隊列,并通知FinalizerThread去消費等操作。關(guān)于finalize方法的使用可以和該引用和串起來思考,后邊有必要再總結(jié)一篇關(guān)于finalize的文章。
?
7. 打印GC引用日志:
-XX:+PrintGCDetails
0.194:?[GC?(System.gc())?0.196:?[SoftReference,?0?refs,?0.0000125?secs]0.196:?[WeakReference,?11?refs,?0.0000064?secs]0.196:?[FinalReference,?37?refs,?0.0000138?secs]0.196:?[PhantomReference,?0?refs,?0?refs,?0.0000058?secs]0.196:?[JNI?Weak?Reference,?0.0000417?secs]
0.196:?[Full?GC?(System.gc())?0.197:?[SoftReference,?0?refs,?0.0000115?secs]0.197:?[WeakReference,?3?refs,?0.0000071?secs]0.197:?[FinalReference,?0?refs,?0.0000077?secs]0.197:?[PhantomReference,?0?refs,?0?refs,?0.0000074?secs]0.197:?[JNI?Weak?Reference,?0.0000276?secs]
?
8. 總結(jié)
????? 通過對SoftReference,WeakReference,PhantomReference,FinalReference 的介紹,可以看出JDK提供這些類型的reference 主要是用來和GC交互的,根據(jù)reference的不同,讓JVM采用不同策略來進行對對象的回收(reclaim)。softly-reachable的referent在保證在OutOfMemoryError之前回收對象,weakly-reachable的referent在發(fā)生GC時就會被回收,finalizer型的reference 主要提供GC前對referent進行finalize執(zhí)行機制。同時這些reference和referenceQueue在一起提供通知機制,PhantomReference的作用就是僅僅就是提供對象回收通知機制,Finalizer借助這種機制實現(xiàn)referent的finalize執(zhí)行,SoftReference、WeakReference也可以配合referenceQueue使用,實現(xiàn)對象回收通知機制。
?
總結(jié)
以上是生活随笔為你收集整理的Java对象的引用类型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JQuery AJAX请求结果的null
- 下一篇: 深入浅出 Java CMS 学习笔记