【Java】强软弱虚四种引用,弱引用在ThreadLocal中的应用
Java中的引用類型 - 強(qiáng)軟虛弱
1、強(qiáng)引用(StrongReference)
Object strongReference = new Object();只要有引用指向它,就不會被回收。當(dāng)內(nèi)存空間不足時,Java虛擬機(jī)寧愿拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具有強(qiáng)引用的對象來解決內(nèi)存不足的問題。
如果強(qiáng)引用對象不使用時,需要 strongReference = null;從而使GC能夠回收
2、軟引用(SoftReference)
內(nèi)存空間不夠時,弱引用會被回收
設(shè)置堆內(nèi)存最大20M
插入15M的強(qiáng)引用之后,堆空間不足了,軟引用被干掉了。(只是SR指向的對象GC掉,SR本身沒有被GC掉)
軟引用有什么作用?緩存可以做成軟引用:內(nèi)存不夠的時候,回收這些對象的內(nèi)存即可。
(比如需要讀取讀取大量的圖片如果每次從硬盤讀,則會影響性能,都放入內(nèi)存中則可能造成緩存溢出,此時可以使用HashMap存放圖片地址和相應(yīng)圖片對象關(guān)聯(lián)的軟引用之間的映射關(guān)系,在內(nèi)存不足時會自動回收該類對象從而避免內(nèi)存溢出)
3、弱引用(WeakReference)
弱引用與軟引用的區(qū)別在于:只具有弱引用的對象擁有更短暫的生命周期。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對象,不管當(dāng)前內(nèi)存空間足夠與否,都會回收它的內(nèi)存。不過,由于垃圾回收器是一個優(yōu)先級很低的線程,因此不一定會很快發(fā)現(xiàn)那些只具有弱引用的對象。
只要發(fā)生垃圾回收,弱引用就會被回收。
在ThreadLocal中會使用,是本文重點。
4、虛引用(PhantomReference)
虛引用是給寫JVM虛擬機(jī)的人管理堆外內(nèi)存用的,普通開發(fā)人員基本用不到
虛引用顧名思義,就是形同虛設(shè),使用get也無法獲取到虛引用的值。與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時候都可能被垃圾回收器回收。
應(yīng)用場景:
虛引用主要用來跟蹤對象被垃圾回收器回收的活動。
用來管理直接內(nèi)存。
直接內(nèi)存(堆外內(nèi)存):不歸JVM管理,GC清理不到,可以歸JVM管,即HotSpot的C++程序管理。這部分內(nèi)存常用于NIO,通過堆中引用指向堆外內(nèi)存(網(wǎng)卡取到的數(shù)據(jù)),不需要自己拷貝,稱為ZeroCopy
虛引用與軟引用和弱引用的一個區(qū)別在于:
虛引用必須和引用隊列(ReferenceQueue)聯(lián)合使用。
當(dāng)垃圾回收器準(zhǔn)備回收一個對象時,如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內(nèi)存之前,把這個虛引用加入到與之關(guān)聯(lián)的引用隊列中。
作用:當(dāng)對象被回收的時候,會接收到一個通知,這個通知被放在一個隊列中。對象的引用被放進(jìn)隊列中。需要另外一個線程不斷檢測這個隊列,如果隊列中有東西,就去進(jìn)行處理。
虛引用目前在JVM只有一個作用:管理堆外內(nèi)存。
堆外內(nèi)存包括:方法區(qū)、NIO的直接Buffer(DirectByteBuffer)。
一個對象指向堆外內(nèi)存,GC是無法將這個堆外內(nèi)存檢測出來并干掉的。
那么,如何管理堆外內(nèi)存呢?
使用虛引用。將指向堆外內(nèi)存的對象用虛引用指向它,這個引用被回收的時候會被讓進(jìn)隊列里。于是,需要進(jìn)行:
1.在JVM堆里面把它干掉。
2.在堆外內(nèi)存把它回收掉。
如果你要手寫一個Netty的話,你可能會需要去清理堆外內(nèi)存…
堆外內(nèi)存怎么回收?
C/C++寫的話,你直接free/delete就行
Java寫的話,UnSafe類里面有個allocateMemory()直接分配內(nèi)存方法
1.8可以用反射機(jī)制來用,1.9之后就不能拿來用了
關(guān)于方法區(qū):在1.8之前叫永久代,在1.8之后叫metaspace
弱引用在ThreadLocal中的作用
什么是ThreadLocal
關(guān)于ThreadLocal
問:想要在d方法中使用x變量,怎么辦?如果把x設(shè)為static,則線程不安全
ThreadLocal提供了線程內(nèi)存儲變量的能力,這些變量不同之處在于每一個線程讀取的變量是對應(yīng)的互相獨立的。通過get和set方法就可以得到當(dāng)前線程對應(yīng)的值。
ThreadLocal:線程引用對象,線程之間不共享
例如,Spring中的@Transactional聲明式事務(wù),比如connection線程池,就是需要在很多方法中調(diào)用同一個連接,從而實現(xiàn)僅有一個事務(wù)。這個方法是不能設(shè)置為static的。在這種情況下,使用ThreadLocal解決這個問題。把連接放在ThreadLocal中之后,線程和線程之間的Connection就隔開了。
Spring的TransactionManager可以給每一個線程開啟一個Connection,這樣不會相互影響。
ThreadLocal的Set方法源碼
1、每一個線程都有自己的Map,里面可以裝K,V對
2、Set的時候,首先拿到當(dāng)前線程,然后拿到當(dāng)前線程的Map,然后將this, valueset進(jìn)map中。這里的this指的是ThreadLocal對象。
在不使用ThreadLocal變量時,應(yīng)該手動調(diào)用remove()方法,不然還是會有內(nèi)存泄漏。
k,v是通過一個弱引用指向的。
JVM使用虛引用讓Key指向ThreadLocal,為什么會這么設(shè)計呢?
因為如果使用強(qiáng)引用,可能會產(chǎn)生內(nèi)存泄漏(tl=null;tl 生命周期結(jié)束之后,ThreadLocal本應(yīng)該被回收,但是如果線程沒結(jié)束(服務(wù)器中很多線程是永遠(yuǎn)不結(jié)束的),Map里面裝的東西就結(jié)束不掉,總會有這個Key指向ThreadLocal,經(jīng)年累月會產(chǎn)生內(nèi)存占用過多的問題)
總結(jié)
以上是生活随笔為你收集整理的【Java】强软弱虚四种引用,弱引用在ThreadLocal中的应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java】线程创建方式:Callabl
- 下一篇: java美元兑换,(Java实现) 美元