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