分享JVM 的四種引用方式
前言
Java中提供這四種引用類型主要有兩個(gè)目的:
- 可以讓程序員通過代碼的方式?jīng)Q定某些對(duì)象的生命周期;
- 有利于JVM進(jìn)行垃圾回收
java.lang.ref包下的引用類結(jié)構(gòu)圖:
一、強(qiáng)引用
特點(diǎn):GC時(shí),永遠(yuǎn)不會(huì)被回收
是指創(chuàng)建一個(gè)對(duì)象并把這個(gè)對(duì)象賦給一個(gè)引用變量。
比如:
Object object = new Object(); String str = "hello"
強(qiáng)引用有引用變量指向時(shí)永遠(yuǎn)不會(huì)被垃圾回收,JVM寧愿拋出OutOfMemory錯(cuò)誤也不會(huì)回收這種對(duì)象。
public void fun1() { Object object = new Object(); Object[] objArr = new Object[1000]; }
當(dāng)運(yùn)行至Object[] objArr = new Object[1000];這句時(shí),如果內(nèi)存不足,JVM會(huì)拋出OOM錯(cuò)誤也不會(huì)回收object指向的對(duì)象。不過要注意的是,當(dāng)fun1運(yùn)行完之后,object和objArr都已經(jīng)不存在了,所以它們指向的對(duì)象都會(huì)被JVM回收。
如果想中斷強(qiáng)引用和某個(gè)對(duì)象之間的關(guān)聯(lián),可以顯示地將引用賦值為null,這樣一來的話,JVM在合適的時(shí)間就會(huì)回收該對(duì)象。比如Vector類的clear方法中就是通過將引用賦值為null來實(shí)現(xiàn)清理工作的
強(qiáng)引用也是導(dǎo)致內(nèi)存泄露的主要原因
二、軟引用
特點(diǎn):內(nèi)存不足時(shí)(自動(dòng)觸發(fā)GC),會(huì)被回收
如果一個(gè)對(duì)象具有軟引用,內(nèi)存空間足夠,垃圾回收器就不會(huì)回收它;如果內(nèi)存空間不足了,就會(huì)回收這些對(duì)象的內(nèi)存。只要垃圾回收器沒有回收它,該對(duì)象就可以被程序使用。軟引用可用來實(shí)現(xiàn)內(nèi)存敏感的高速緩存,比如網(wǎng)頁緩存、圖片緩存等。使用軟引用能防止內(nèi)存泄露,增強(qiáng)程序的健壯性。
SoftReference的特點(diǎn)是它的一個(gè)實(shí)例保存對(duì)一個(gè)Java對(duì)象的軟引用, 該軟引用的存在不妨礙垃圾收集線程對(duì)該Java對(duì)象的回收。也就是說,一旦SoftReference保存了對(duì)一個(gè)Java對(duì)象的軟引用后,在垃圾線程對(duì) 這個(gè)Java對(duì)象回收前,SoftReference類所提供的get()方法返回Java對(duì)象的強(qiáng)引用。另外,一旦垃圾線程回收該Java對(duì)象之 后,get()方法將返回null。
示例:
JVM參數(shù) -Xms10m -Xmx10m -XX:+PrintGCDetails
public static void main(String[] args) { Object obj = new Object(); SoftReference<Object> softRef = new SoftReference<Object>(obj); System.out.println(obj); System.out.println(softRef.get()); // 對(duì)象要設(shè)置為null,否則不會(huì)被回收。原因:通過設(shè)置為null讓對(duì)象失去引用,方便GC // 備注:因?yàn)樵谶@個(gè)main方法中(主線程),方法未結(jié)束之前,不設(shè)置為null,對(duì)象是不會(huì)失去引用的。 obj = null; // 當(dāng)內(nèi)存不足時(shí),會(huì)自動(dòng)觸發(fā)GC操作,這里就無需手動(dòng)GC try { byte[] b = new byte[30 * 1024 * 1024]; } catch (Exception e) { // TODO: handle exception } finally { System.out.println(obj); System.out.println(softRef.get()); } }
上述示例說明,軟引用在內(nèi)存不夠時(shí),通過系統(tǒng)的GC,回收對(duì)象了
假如有一個(gè)應(yīng)用需要讀取大量的本地圖片:
- 如果每次讀取圖片都從硬盤中讀取則會(huì)嚴(yán)重影響性能
- 如果一次全部加載到內(nèi)存中又可能會(huì)造成內(nèi)存溢出
此時(shí)使用軟引用可以解決這個(gè)問題。
設(shè)計(jì)思路:用一個(gè)HashMap來保存圖片的路徑的相應(yīng)圖片對(duì)象關(guān)聯(lián)的軟引用之間的映射關(guān)系,在內(nèi)存不足時(shí),JVM會(huì)自動(dòng)回收這些緩存圖片對(duì)象所占用的空間,從而有效地避免OOM的問題。
Map<String, SoftRefrence<Bitmap>> imageCache = new HashMap<String, SoftRefrence<Bitmap>>();
三、弱引用
特點(diǎn):無論內(nèi)存是否充足,只要進(jìn)行GC,都會(huì)被回收
引用也是用來描述非必需對(duì)象的,當(dāng)JVM進(jìn)行垃圾回收時(shí),無論內(nèi)存是否充足,都會(huì)回收被弱引用關(guān)聯(lián)的對(duì)象。在java中,用java.lang.ref.WeakReference類來表示
示例:
public static void main(String[] args) { Object obj = new Object(); WeakReference<Object> weakRef = new WeakReference<Object>(obj); System.out.println(obj); // java.lang.Object@7852e922 System.out.println(weakRef.get()); // java.lang.Object@7852e922 // 對(duì)象要設(shè)置為null,否則不會(huì)被回收。原因:通過設(shè)置為null讓對(duì)象失去引用,方便GC // 備注:因?yàn)樵谶@個(gè)main方法中(主線程),方法未結(jié)束之前,不設(shè)置為null,對(duì)象是不會(huì)失去引用的。 obj = null; // 這里通過手動(dòng)觸發(fā)GC操作。否則內(nèi)存充足的情況下很難自動(dòng)觸發(fā)GC System.gc(); System.out.println(obj); // null System.out.println(weakRef.get()); // null }
上述示例表明,在內(nèi)存充足的情況下,弱引用的對(duì)象也被回收了。
WeakHashMap的用法
public static void main(String[] args) { WeakHashMap<String, String> weakMap = new WeakHashMap<String, String>(); String key = "1"; weakMap.put(key, "test"); System.out.println(weakMap); // {1=test} System.out.println(weakMap.get(key)); // test key = null; System.gc(); System.out.println(weakMap); // {1=test} System.out.println(weakMap.get(key)); // null }
軟引用和弱引用的使用場(chǎng)景:mybatis中的緩存
四、虛引用
特點(diǎn):如同虛設(shè),和沒有引用沒什么區(qū)別
虛引用和前面的軟引用、弱引用不同,它并不影響對(duì)象的生命周期。在java中用java.lang.ref.PhantomReference類表示。如果一個(gè)對(duì)象與虛引用關(guān)聯(lián),則跟沒有引用與之關(guān)聯(lián)一樣,在任何時(shí)候都可能被垃圾回收器回收。
要注意的是,虛引用必須和引用隊(duì)列關(guān)聯(lián)使用,當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來了解被引用的對(duì)象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)。
示例:
public static void main(String[] args) { Object obj = new Object(); ReferenceQueue<String> queue = new ReferenceQueue<String>(); PhantomReference<String> pr = new PhantomReference<String>(obj, queue); System.out.println(pr.get()); // null }
虛引用的主要作用是跟蹤對(duì)象被垃圾回收的狀態(tài)。僅僅是提供了一種確保對(duì)象被finalize以后,做某些事情的機(jī)制。PhantomRefrence的get方法總是返回null,因此無法訪問對(duì)應(yīng)的引用對(duì)象。其意義在于說明一個(gè)對(duì)象已經(jīng)進(jìn)入finalization階段,可以被GC回收,用來實(shí)現(xiàn)比finalization機(jī)制更靈活的回收操作。
換句話說,設(shè)置虛引用關(guān)聯(lián)的唯一目的,就是在這個(gè)對(duì)象被收集器回收的時(shí)候收到一個(gè)系統(tǒng)通知或者后續(xù)添加進(jìn)一步的處理。Java技術(shù)允許使用finalize()方法在垃圾收集器將對(duì)象從內(nèi)存中清除之前做必要的清理工作。
引用隊(duì)列的用法:
public static void main(String[] args) { Object obj = new Object(); ReferenceQueue<Object> queue = new ReferenceQueue<Object>(); WeakReference<Object> weakRef = new WeakReference<Object>(obj, queue); System.out.println(obj); // java.lang.Object@7852e922 System.out.println(weakRef.get()); // java.lang.Object@7852e922 System.out.println(queue.poll()); // null obj = null; System.gc(); System.out.println(obj); // null System.out.println(weakRef.get()); // null System.out.println(queue.poll()); // java.lang.ref.WeakReference@4e25154f }
到此這篇關(guān)于分享JVM 的四種引用方式的文章就介紹到這了,更多相關(guān)JVM 引用方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring @Scheduled注解的使用誤區(qū)及解決
這篇文章主要介紹了spring @Scheduled注解的使用誤區(qū)及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11JavaEE Filter敏感詞過濾的方法實(shí)例詳解
我們無論是在聊天還是在留言時(shí),都有一些信息不希望別人看到。那么如果過濾這些關(guān)鍵詞呢?下面小編給大家分享JavaEE Filter敏感詞過濾的方法實(shí)例詳解,感興趣的朋友一起學(xué)習(xí)吧2016-05-05spring boot配置MySQL數(shù)據(jù)庫(kù)連接、Hikari連接池和Mybatis的簡(jiǎn)單配置方法
這篇文章主要介紹了spring boot配置MySQL數(shù)據(jù)庫(kù)連接、Hikari連接池和Mybatis的簡(jiǎn)單配置方法,需要的朋友可以參考下2018-03-03SpringBoot配置log4j2的實(shí)現(xiàn)示例
SpringBoot中默認(rèn)使用Logback作為日志框架,本文主要介紹了SpringBoot配置log4j2的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12BeanUtils.copyProperties()參數(shù)的賦值順序說明
這篇文章主要介紹了BeanUtils.copyProperties()參數(shù)的賦值順序說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09