您好,登錄后才能下訂單哦!
這篇文章主要介紹“Java中引用方法有哪些”,在日常操作中,相信很多人在Java中引用方法有哪些問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對(duì)大家解答”Java中引用方法有哪些”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!
java 中的 4 種引用方式,適用于不同的場(chǎng)景,重點(diǎn)需要理解虛引用,結(jié)合文字和代碼
被強(qiáng)引用的對(duì)象,不會(huì)被垃圾回收器回收,JVM 寧愿拋出 OOM 也不會(huì)去回收被強(qiáng)引用的對(duì)象;
M m = new M();
當(dāng)堆空間夠用時(shí),GC 不會(huì)對(duì)軟引用的對(duì)象進(jìn)行回收,當(dāng)堆空間不足以分配新的空間時(shí),觸發(fā) GC 就會(huì)對(duì)這部分對(duì)象進(jìn)行回收,通常用在緩存等領(lǐng)域。將緩存對(duì)象使用軟引用,空間不足的時(shí)候釋放這部分空間,需要再次使用的時(shí)候,重新從 DB 中加載即可。
另外軟引用可以配合隊(duì)列(ReferenceQueue
) 來使用,如果軟引用引用的對(duì)象被垃圾回收,JVM 會(huì)把軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
/** * 軟引用:一般用在緩存,只要空間不足,GC 跑起來就會(huì)回收它 * 運(yùn)行參數(shù) -Xmx200m -XX:+PrintGC * Created by etfox on 2021/03/01 17:06 **/ public class TestSoftReference { public static void main(String[] ags) throws InterruptedException { //100M的緩存數(shù)據(jù) byte[] cacheData = new byte[100 * 1024 * 1024]; //將緩存數(shù)據(jù)用軟引用持有 SoftReference<byte[]> cacheRef = new SoftReference<>(cacheData); //將緩存數(shù)據(jù)的強(qiáng)引用去除 cacheData = null; System.out.println("第一次GC前" + cacheData); System.out.println("第一次GC前" + cacheRef.get()); //進(jìn)行一次GC后查看對(duì)象的回收情況 System.gc(); //等待GC Thread.sleep(500); System.out.println("第一次GC后" + cacheData); System.out.println("第一次GC后" + cacheRef.get()); //在分配一個(gè)120M的對(duì)象,看看緩存對(duì)象的回收情況 byte[] newData = new byte[120 * 1024 * 1024]; System.out.println("分配后" + cacheData); System.out.println("分配后" + cacheRef.get()); } } console==> [GC (Allocation Failure) 4120K->1055K(15872K), 0.0016237 secs] [Full GC (Allocation Failure) 1055K->1054K(15872K), 0.0015426 secs] 第一次GC前null 第一次GC前[B@1973e9b [Full GC (System.gc()) 103583K->103455K(118340K), 0.0015559 secs] 第一次GC后null 第一次GC后[B@1973e9b [GC (Allocation Failure) 105575K->103455K(198016K), 0.0001733 secs] [Full GC (Allocation Failure) 103455K->103455K(198016K), 0.0011860 secs] [Full GC (Allocation Failure) 103455K->819K(198016K), 0.0012080 secs] 分配后null 分配后null
弱引用的引用對(duì)象在每次 GC 時(shí),不管當(dāng)前堆內(nèi)存大小,都會(huì)將這個(gè)對(duì)象清除。如果此對(duì)象偶爾使用,并且希望需要用到的時(shí)候可以獲取到,但是又不希望影響這個(gè)對(duì)象的回收,就可以使用弱引用來描述對(duì)象。
當(dāng)然弱引用也可以結(jié)合事件隊(duì)列使用。
/** * 弱引用:如果對(duì)象時(shí)偶爾使用,并且希望使用的時(shí)候就能獲取到(get),但是又不想影響此對(duì)象的垃圾收集 * 可以引入隊(duì)列 * Created by etfox on 2021/03/01 17:59 **/ public class TestWeakReference { public static void main(String[] args) throws InterruptedException { //100M的緩存數(shù)據(jù) byte[] cacheData = new byte[100 * 1024 * 1024]; //將緩存數(shù)據(jù)用軟引用持有 WeakReference<byte[]> cacheRef = new WeakReference<>(cacheData); System.out.println("第一次GC前" + cacheData); System.out.println("第一次GC前" + cacheRef.get()); //進(jìn)行一次GC后查看對(duì)象的回收情況 System.gc(); //等待GC Thread.sleep(500); System.out.println("第一次GC后" + cacheData); System.out.println("第一次GC后" + cacheRef.get()); //將緩存數(shù)據(jù)的強(qiáng)引用去除 cacheData = null; System.gc(); //等待GC Thread.sleep(500); System.out.println("第二次GC后" + cacheData); System.out.println("第二次GC后" + cacheRef.get()); } } console==> [GC (Allocation Failure) 3912K->1025K(15872K), 0.0016372 secs] [Full GC (Allocation Failure) 1025K->1024K(15872K), 0.0014157 secs] 第一次GC前[B@1973e9b 第一次GC前[B@1973e9b [Full GC (System.gc()) 103723K->103456K(118340K), 0.0016463 secs] 第一次GC后[B@1973e9b 第一次GC后[B@1973e9b [Full GC (System.gc()) 105601K->1056K(198016K), 0.0012771 secs] 第二次GC后null 第二次GC后null
虛引用,顧名思義是虛幻的,虛引用的對(duì)象并不能在 get 的時(shí)候獲取到它。它也在我們?nèi)粘i_發(fā)中沒有適用的場(chǎng)景,它的主要作用是用來跟蹤一個(gè)對(duì)象的生命周期 (通常來說是直接內(nèi)存 [JDK1.5 Java 中除了由 JVM 管理的空間,還可以在內(nèi)存中直接分配對(duì)象]中的對(duì)象),一般使用在 JVM 的開發(fā)中,主要用來管理直接內(nèi)存,因?yàn)橹苯觾?nèi)存通常 GC 無法管理這一塊內(nèi)存(C++ delete 完事),需要特殊處理。
例如 NIO 的 ByteBuffer.allocateDirect(1024); 分配內(nèi)存到直接內(nèi)存空間中,通常來說從網(wǎng)卡中讀取的數(shù)據(jù),由操作系統(tǒng)讀取到直接內(nèi)存中,在需要使用的時(shí)候,需要拷貝到 JVM 堆空間中,如果不使用 allocateDirect 就需要一個(gè)拷貝的過程,這是非常消耗時(shí)間的,
// |-- ---| | --------| |------------|
// | 網(wǎng)卡 | ==> | 直接內(nèi)存 | == copy ==> | JVM 堆空間 |
// |--- --| | ------- | |------------|
使用直接存內(nèi)存省略了拷貝的過程,俗稱 nio 的 zero copy,但是直接內(nèi)存中的對(duì)象在不需要使用的時(shí)候無法通過正常 GC 過程去管理這一塊空間,所以用到了虛引用,
解釋:
虛引用需要配合一個(gè)事件隊(duì)列一起使用,JVM GC 的時(shí)候并不是說把虛引用的引用清理掉完事,而是說會(huì)把虛引用的引用放到事件隊(duì)列當(dāng)中,垃圾回收線程會(huì)時(shí)不時(shí)的去檢查這個(gè)事件隊(duì)列,看一下引用的回收過程需不需要做一些后續(xù)善后處理(例如清理直接內(nèi)存中的對(duì)象,這玩意兒由實(shí)現(xiàn)人去弄)這就是虛引用的作用和含義了。
/** * 虛引用:可以通過隊(duì)列跟蹤一個(gè)對(duì)象的生命周期,一般在寫 JVM 相關(guān)的時(shí)候才會(huì)用到虛引用,主要用來管理直接內(nèi)存(C++ delete 一下子完事) * -Xmx20m -XX:+PrintGC * Created by etfox on 2021/03/03 12:14 **/ public class TestPhantomReference { private static final List<Object> LIST = new LinkedList<>(); private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>(); public static void main(String[] args) throws InterruptedException { final PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE); // 永遠(yuǎn)都會(huì)返回 null System.out.println(phantomReference.get()); // ByteBuffer.allocateDirect(1024); 分配內(nèi)存到操作系統(tǒng)的空間,直接內(nèi)存的空間, JDK 1.5 // 通常從網(wǎng)卡讀取的數(shù)據(jù),通常由系統(tǒng)讀取到直接內(nèi)存里面,如果想用,需要拷貝到 JVM 堆空間里 // 如果不使用 allocateDirect(直接內(nèi)存) 就需要一個(gè)拷貝的過程,是非常消耗時(shí)間的 // |-- ---| | --------| |------------| // | 網(wǎng)卡 | ==> | 直接內(nèi)存 | == copy ==> | JVM 堆空間 | // |--- --| | ------- | |------------| // 使用直接內(nèi)存省略了拷貝的過程,俗稱 nio zero copy // 但是直接內(nèi)存中的對(duì)象在不再需要的時(shí)候無法由 JVM 去 GC 清理內(nèi)存,所以用到了虛引用 // 虛引用需要和一個(gè)隊(duì)列一起使用,JVM GC 時(shí)并不是說會(huì)把虛引用的引用清理,而是說會(huì)把虛引用的引用放到事件隊(duì)列中 // 垃圾回收線程可以時(shí)不時(shí)的檢查這個(gè)事件隊(duì)列,看一下這個(gè)引用的回收過程需不需要做一些善后處理(例如清理直接內(nèi)存的那個(gè)對(duì)象) // 這就是虛引用的作用和含義 ByteBuffer b = ByteBuffer.allocateDirect(1024); new Thread(new Runnable() { @Override public void run() { while (true) { LIST.add(new byte[1024 * 1024]); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(phantomReference.get()); } } }).start(); // 模擬垃圾回收線程 new Thread(new Runnable() { @Override public void run() { while (true) { Reference<? extends M> poll = QUEUE.poll(); if (poll != null) { System.out.println("虛引用對(duì)象被 JVM 回收了 " + poll); } } } }).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } public static class M { @Override protected void finalize() throws Throwable { System.out.println("當(dāng)對(duì)象將被回收時(shí), GC 會(huì)調(diào)用當(dāng)前方法"); } } } console==> null [GC (Allocation Failure) 3493K->1061K(15872K), 0.0017311 secs] 當(dāng)對(duì)象將被回收時(shí), GC 會(huì)調(diào)用當(dāng)前方法 null null null [GC (Allocation Failure) 4483K->4132K(15872K), 0.0020184 secs] null null null null [GC (Allocation Failure) 8299K->8228K(15872K), 0.0017350 secs] null null null null [GC (Allocation Failure) 12401K->12324K(17928K), 0.0016853 secs] [Full GC (Allocation Failure) 12324K->12324K(17928K), 0.0011354 secs] 虛引用對(duì)象被 JVM 回收了 java.lang.ref.PhantomReference@d5fbc1 null null null null null [Full GC (Allocation Failure) 17599K->17445K(19840K), 0.0019903 secs] null [Full GC (Allocation Failure) 18524K->18469K(19840K), 0.0011629 secs] [Full GC (Allocation Failure) 18469K->18232K(19840K), 0.0022320 secs] Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space at com.pangu.TestPhantomReference$1.run(TestPhantomReference.java:41) at java.lang.Thread.run(Thread.java:748)
到此,關(guān)于“Java中引用方法有哪些”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。