日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術文章
文章詳情頁

深入了解JAVA 軟引用

瀏覽:130日期:2022-08-27 08:25:07

定義

軟引用是使用SoftReference創建的引用,強度弱于強引用,被其引用的對象在內存不足的時候會被回收,不會產生內存溢出。

說明

軟引用,顧名思義就是比較“軟”一點的引用。

當一個對象與GC Roots之間存在強引用時,無論何時都不會被GC回收掉。如果一個對象與GC Roots之間沒有強引用與其關聯而存在軟引用關聯時,那么垃圾回收器對它的態度就取決于內存的緊張程度了。如果內存空間足夠,垃圾回收器就不會回收這個對象,但如果內存空間不足了,它就難逃被回收的厄運。

如果一個對象與GC Roots之間不存在強引用,但是存在軟引用,則稱這個對象為軟可達(soft reachable)對象。

在垃圾回收器沒有回收它的時候,軟可達對象就像強可達對象一樣,可以被程序正常訪問和使用,但是需要通過軟引用對象間接訪問,需要的話也能重新使用強引用將其關聯。所以軟引用適合用來做內存敏感的高速緩存。

String s = new String('Frank'); // 創建強引用與String對象關聯,現在該String對象為強可達狀態SoftReference<String> softRef = new SoftReference<String>(s); // 再創建一個軟引用關聯該對象s = null; // 消除強引用,現在只剩下軟引用與其關聯,該String對象為軟可達狀態s = softRef.get(); // 重新關聯上強引用

這里變量s持有對字符串對象的強引用,而softRef持有對該對象的軟引用,所以當執行s = null后,字符串對象就只剩下軟引用了,這時如果因為內存不足發生Full GC,就會把這個字符串對象回收掉。

注意,在垃圾回收器回收一個對象前,SoftReference類所提供的get方法會返回Java對象的強引用,一旦垃圾線程回收該對象之后,get方法將返回null。所以在獲取軟引用對象的代碼中,一定要先判斷返回是否為null,以免出現NullPointerException異常而導致應用崩潰。

下面的代碼會讓s再次持有對象的強引用:

s = softRef.get();

如果在softRef指向的對象被回收前,用強引用指向該對象,那這個對象又會變成強可達。

來看一個使用SoftReference的栗子:

public class TestA { static class OOMClass{ private int[] oom = new int[1024 * 100];// 100KB } public static void main(String[] args) throws InterruptedException { ReferenceQueue<OOMClass> queue = new ReferenceQueue<>(); List<SoftReference> list = new ArrayList<>(); while(true){ for (int i = 0; i < 100; i++) {list.add(new SoftReference<OOMClass>(new OOMClass(), queue)); } Thread.sleep(500); } }}

注意,ReferenceQueue中聲明的類型為OOMClass,即與SoftReference引用的類型一致。

設置一下虛擬機參數:

-verbose:gc -Xms4m -Xmx4m -Xmn2m

運行結果:

[GC (Allocation Failure) 1017K->432K(3584K), 0.0017239 secs][GC (Allocation Failure) 1072K->472K(3584K), 0.0099237 secs][GC (Allocation Failure) 1323K->1296K(3584K), 0.0009528 secs][GC (Allocation Failure) 2114K->2136K(3584K), 0.0009951 secs][Full GC (Ergonomics) 2136K->1992K(3584K), 0.0040658 secs][Full GC (Ergonomics) 2807K->2791K(3584K), 0.0036280 secs][Full GC (Allocation Failure) 2791K->373K(3584K), 0.0032477 secs][Full GC (Ergonomics) 2786K->2773K(3584K), 0.0034554 secs][Full GC (Allocation Failure) 2773K->373K(3584K), 0.0032667 secs][Full GC (Ergonomics) 2798K->2775K(3584K), 0.0036231 secs][Full GC (Allocation Failure) 2775K->375K(3584K), 0.0055482 secs][Full GC (Ergonomics) 2799K->2776K(3584K), 0.0031358 secs]...省略n次GC信息

在TestA中,我們使用死循環不斷的往list中添加新對象,如果是強引用,會很快因為內存不足而拋出OOM,因為這里的堆內存大小設置為了4M,而一個對象就有100KB,一個循環添加100個對象,也就是差不多10M,顯然一個循環都跑不完就會內存不足,而這里,因為使用的是軟引用,所以JVM會在內存不足的時候將軟引用回收掉。

[Full GC (Allocation Failure) 2791K->373K(3584K), 0.0032477 secs]

從這一條可以看出,在內存不足發生Full GC時,回收掉了大部分的軟引用指向的對象,釋放了大量的內存。

因為這里新生代只分配了2M,所以很快就會發生GC,如果你的程序運行沒有看到這個結果,請先確認一下虛擬機參數是否設置正確,如果設置正確還是沒有看到,那么將循環次數由1000改為10000或者100000在試試看。

應用場景

軟引用關聯的對象,只有在內存不足的時候JVM才會回收該對象。這一點可以很好地用來解決OOM的問題,并且這個特性很適合用來實現緩存:比如網頁緩存、圖片緩存等。

現在考慮這樣一個場景 ,在很多應用中,都會出現大量的默認圖片,比如說QQ的默認頭像,應用內的默認圖標等等,這些圖片很多地方會用到。

如果每次都去讀取圖片,由于讀取文件速度較慢,大量重復的讀取會導致性能下降。所以可以考慮將圖片緩存起來,需要的時候直接從內存中讀取。但是,由于圖片占用內存空間比較大,緩存的圖片過多會占用比較多的內存,就可能比較容易發生OOM。這時候,軟引用就派得上用場了。

注意,SoftReference對象是用來保存軟引用的,但它同時也是一個Java對象。所以,當軟可及對象被回收之后,雖然這個SoftReference對象的get()方法返回null,但SoftReference對象本身并不是null,而此時這個SoftReference對象已經不再具有存在的價值,需要一個適當的清除機制,避免大量SoftReference對象帶來的內存泄漏。

ReferenceQueue就是用來保存這些需要被清理的引用對象的。軟引用可以和一個引用隊列(ReferenceQueue)聯合使用,如果軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

下面用SoftReference來實現一個簡單的緩存類:

public class SoftCache<T> { // 引用隊列 private ReferenceQueue<T> referenceQueue = new ReferenceQueue<>(); // 保存軟引用集合,在引用對象被回收后銷毀 private List<Reference<T>> list = new ArrayList<>(); // 添加緩存對象 public synchronized void add(T obj){ // 構建軟引用 Reference<T> reference = new SoftReference<T>(obj, referenceQueue); // 加入列表中 list.add(reference); } // 獲取緩存對象 public synchronized T get(int index){ // 先對無效引用進行清理 clear(); if (index < 0 || list.size() < index){ return null; } Reference<T> reference = list.get(index); return reference == null ? null : reference.get(); } public int size(){ return list.size(); } @SuppressWarnings('unchecked') private void clear(){ Reference<T> reference; while (null != (reference = (Reference<T>) referenceQueue.poll())){ list.remove(reference); } }}

然后測試一下這個緩存類:

public class SoftCacheTest { private static int num = 0; public static void main(String[] args){ SoftCache<OOMClass> softCache = new SoftCache<>(); for (int i = 0; i < 40; i++) { softCache.add(new OOMClass('OOM Obj-' + ++num)); } System.out.println(softCache.size()); for (int i = 0; i < softCache.size(); i++) { OOMClass obj = softCache.get(i); System.out.println(obj == null ? 'null' : obj.name); } System.out.println(softCache.size()); } static class OOMClass{ private String name; private int[] oom = new int[1024 * 100];// 100KB public OOMClass(String name) { this.name = name; } }}

仍使用之前的虛擬機參數:

-verbose:gc -Xms4m -Xmx4m -Xmn2m

運行結果:

[GC (Allocation Failure) 1017K->432K(3584K), 0.0012236 secs][GC (Allocation Failure) 1117K->496K(3584K), 0.0016875 secs][GC (Allocation Failure) 1347K->1229K(3584K), 0.0015059 secs][GC (Allocation Failure) 2047K->2125K(3584K), 0.0018090 secs][Full GC (Ergonomics) 2125K->1994K(3584K), 0.0054759 secs][Full GC (Ergonomics) 2822K->2794K(3584K), 0.0023167 secs][Full GC (Allocation Failure) 2794K->376K(3584K), 0.0036056 secs][Full GC (Ergonomics) 2795K->2776K(3584K), 0.0042365 secs][Full GC (Allocation Failure) 2776K->376K(3584K), 0.0035122 secs][Full GC (Ergonomics) 2795K->2776K(3584K), 0.0054760 secs][Full GC (Allocation Failure) 2776K->376K(3584K), 0.0036965 secs][Full GC (Ergonomics) 2802K->2777K(3584K), 0.0044513 secs][Full GC (Allocation Failure) 2777K->376K(3584K), 0.0041400 secs][Full GC (Ergonomics) 2796K->2777K(3584K), 0.0025255 secs][Full GC (Allocation Failure) 2777K->376K(3584K), 0.0037690 secs][Full GC (Ergonomics) 2817K->2777K(3584K), 0.0037759 secs][Full GC (Allocation Failure) 2777K->377K(3584K), 0.0042416 secs]緩存列表大?。?0OOM Obj-37OOM Obj-38OOM Obj-39OOM Obj-40緩存列表大?。?

可以看到,緩存40個軟引用對象之后,如果一次性全部存儲,顯然內存大小無法滿足,所以在不斷創建軟引用對象的過程中,不斷發生GC來進行垃圾回收,最終只有4個軟引用未被清理掉。

強引用與軟引用對比

沒有對比就沒有傷害,來將強引用和軟引用對比一下:

public class Test { static class OOMClass{ private int[] oom = new int[1024]; } public static void main(String[] args) { testStrongReference(); //testSoftReference(); } public static void testStrongReference(){ List<OOMClass> list = new ArrayList<>(); for (int i = 0; i < 1000; i++) { list.add(new OOMClass()); } } public static void testSoftReference(){ ReferenceQueue<OOMClass> referenceQueue = new ReferenceQueue<>(); List<SoftReference> list = new ArrayList<>(); for (int i = 0; i < 1000; i++) { OOMClass oomClass = new OOMClass(); list.add(new SoftReference(oomClass, referenceQueue)); oomClass = null; } }}

運行testStrongReference方法的結果如下:

[GC (Allocation Failure) 1019K->384K(3584K), 0.0033595 secs][GC (Allocation Failure) 1406K->856K(3584K), 0.0013098 secs][GC (Allocation Failure) 1880K->1836K(3584K), 0.0014382 secs][Full GC (Ergonomics) 1836K->1756K(3584K), 0.0039761 secs][Full GC (Ergonomics) 2778K->2758K(3584K), 0.0021269 secs][Full GC (Ergonomics) 2779K->2770K(3584K), 0.0016329 secs][Full GC (Ergonomics) 2779K->2775K(3584K), 0.0023157 secs][Full GC (Ergonomics) 2775K->2775K(3584K), 0.0015927 secs][Full GC (Ergonomics) 3037K->3029K(3584K), 0.0025071 secs][Full GC (Ergonomics) 3067K->3065K(3584K), 0.0017529 secs][Full GC (Allocation Failure) 3065K->3047K(3584K), 0.0033445 secs][Full GC (Ergonomics) 3068K->3059K(3584K), 0.0016623 secs][Full GC (Ergonomics) 3070K->3068K(3584K), 0.0028357 secs][Full GC (Allocation Failure) 3068K->3068K(3584K), 0.0017616 secs]java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid3352.hprof ...Exception in thread 'main' java.lang.OutOfMemoryError: Java heap spaceHeap dump file created [3855956 bytes in 0.017 secs][Full GC (Ergonomics) 3071K->376K(3584K), 0.0032068 secs]at reference.Test$OOMClass.<init>(Test.java:11)at reference.Test.testStrongReference(Test.java:22)at reference.Test.main(Test.java:15)

Process finished with exit code 1

可以看到,很快就拋出了OOM,原因是Java heap space,也就是堆內存不足。

如果運行testSoftReference方法,將會得到如下結果:

[GC (Allocation Failure) 1019K->464K(3584K), 0.0019850 secs][GC (Allocation Failure) 1484K->844K(3584K), 0.0015920 secs][GC (Allocation Failure) 1868K->1860K(3584K), 0.0043236 secs][Full GC (Ergonomics) 1860K->1781K(3584K), 0.0044581 secs][Full GC (Ergonomics) 2802K->2754K(3584K), 0.0041726 secs][Full GC (Ergonomics) 2802K->2799K(3584K), 0.0031293 secs][Full GC (Ergonomics) 3023K->3023K(3584K), 0.0024830 secs][Full GC (Ergonomics) 3071K->3068K(3584K), 0.0035025 secs][Full GC (Allocation Failure) 3068K->405K(3584K), 0.0040672 secs][GC (Allocation Failure) 1512K->1567K(3584K), 0.0011170 secs][Full GC (Ergonomics) 1567K->1496K(3584K), 0.0048438 secs]

可以看到,并沒有拋出OOM,而是進行多次了GC,可以明顯的看到這一條:

[Full GC (Allocation Failure) 3068K->405K(3584K), 0.0040672 secs]

當內存不足時進行了一次Full GC,回收了大部分內存空間,也就是將大部分軟引用指向的對象回收掉了。

小結

軟引用弱于強引用 軟引用指向的對象會在內存不足時被垃圾回收清理掉 JVM會優先回收長時間閑置不用的軟引用對象,對那些剛剛構建的或剛剛使用過的軟引用對象會盡可能保留 軟引用可以有效的解決OOM問題 軟引用適合用作非必須大對象的緩存

至此,本篇就告一段落了,這里只簡單的介紹了軟引用的作用以及用法。其實軟引用并沒有這么好,它的使用有一些可能是致命的缺點,如果想要更深入的了解軟引用的運行原理以及軟引用到底是在何時進行回收,又是如何進行回收的話,可以查看翻閱后續的章節。

以上就是深入了解JAVA 軟引用的詳細內容,更多關于JAVA 軟引用的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
日韩在线短视频| 91精品二区| 日韩理论片av| 国产精品嫩模av在线| 亚洲精品乱码日韩| 红桃视频欧美| 欧美精品一区二区三区精品| 亚洲三级毛片| 伊人久久亚洲| 日韩一区二区免费看| 国产精品99久久久久久董美香| 蜜臀久久99精品久久久久久9| 欧美日韩一二| 亚洲精品高潮| 亚洲一二av| 亚洲精品少妇| 精品伊人久久久| 激情久久99| 精品72久久久久中文字幕| 欧美精选视频一区二区| 成人av三级| 精品免费av在线| 亚洲无线观看| 国产综合激情| 午夜一级在线看亚洲| 国产乱码精品一区二区三区亚洲人| 日韩精品社区| 国产剧情一区| 99视频精品全国免费| 午夜国产精品视频| 视频一区视频二区中文| 欧美天堂一区二区| 在线一区二区三区视频| 亚洲乱码一区| 在线免费观看亚洲| 成人日韩av| 日本va欧美va欧美va精品| 激情丁香综合| 欧美激情aⅴ一区二区三区| 国产精品三p一区二区| 国产精品美女久久久久久不卡| 日韩av一区二| 日韩在线观看一区二区| 在线观看亚洲精品福利片| 国产精品密蕾丝视频下载| 都市激情国产精品| 欧美日韩水蜜桃| 国产精品激情电影| 久久婷婷久久| 国产一区二区三区精品在线观看| 91成人网在线观看| 国产videos久久| 久久影院资源站| 激情综合网址| 欧美 日韩 国产一区二区在线视频 | 国产精品色婷婷在线观看| 日韩精品影视| 亚洲综合精品四区| 欧美综合精品| 国产一区二区三区四区二区| 99视频精品全部免费在线视频| 亚洲一区成人| 国产精品一区二区美女视频免费看| 日韩欧美在线精品| 丝袜诱惑制服诱惑色一区在线观看| 综合激情一区| 精品国产午夜肉伦伦影院| 香蕉国产精品| 欧美激情国产在线| 老司机精品久久| 久久精品国产999大香线蕉| 免费日韩av| 精品国产乱码久久久久久樱花| 99riav1国产精品视频| 天堂а√在线最新版中文在线| 日本久久成人网| 亚洲精品福利| 夜夜精品视频| 国产成人免费精品| 亚洲91网站| 亚洲欧美日韩国产综合精品二区| 国产精品videossex| 国产一区二区高清| 久久电影tv| 国产毛片精品久久| 久久成人一区| 亚洲成人一区在线观看| 蜜桃视频第一区免费观看| 福利一区二区免费视频| 少妇精品久久久| 在线亚洲成人| 日韩免费高清| 国产福利一区二区三区在线播放| 日本不卡一区二区| 欧美成人午夜| 国产精品99一区二区三区| 久久免费精品| 日韩精品久久久久久| 91精品观看| 噜噜噜躁狠狠躁狠狠精品视频 | 激情婷婷亚洲| 国产乱子精品一区二区在线观看| 国产亚洲高清视频| 欧美中文一区二区| 国产一区二区三区亚洲| 国产成人77亚洲精品www| 啪啪亚洲精品| 伊人久久亚洲美女图片| 国产麻豆综合| 久久久久91| 日韩欧美精品| 欧美成人高清| 视频一区中文| 亚洲韩日在线| 水野朝阳av一区二区三区| 亚洲视频综合| 国产成人精品一区二区三区在线| 91日韩在线| 久久男人av资源站| 国产激情在线播放| 亚洲天堂资源| 成人国产精品久久| 日韩在线高清| 在线成人动漫av| 亚洲精品一二三区区别| 亚洲三级网址| 日韩欧美中文在线观看| 伊人网在线播放| 久久久精品午夜少妇| 91亚洲国产高清| 亚洲福利精品| 99久久久久国产精品| 日韩在线高清| 蜜臀av一区二区三区| 在线精品视频一区| 中文字幕亚洲在线观看| 国产精品一级在线观看| 国产精品一页| 精品一区二区男人吃奶| 久久影院一区| 欧美a级一区| 在线日韩欧美| 欧美一级全黄| 国产一区丝袜| 亚洲电影有码| 日韩不卡在线观看日韩不卡视频| 亚洲人成亚洲精品| 老牛国产精品一区的观看方式| 欧美日韩一区二区国产| 国产精品玖玖玖在线资源| 国产激情久久| 激情综合网五月| 热久久免费视频| 超碰在线99| 亚洲欧美日本国产专区一区| 中文字幕一区二区三区日韩精品 | 午夜一级在线看亚洲| 亚洲精品韩国| 亚洲深夜影院| 欧美片网站免费| 国产精品99一区二区三| 国产精品精品| 亚洲区欧美区| 你懂的国产精品永久在线| 成人在线视频区| 日韩在线电影| 水蜜桃久久夜色精品一区| 亚洲日本国产| 日韩av专区| 免费不卡在线观看| 日韩精品影视| 日韩一区二区三区免费视频| 欧美黄色一区| 亚洲乱亚洲高清| 欧美好骚综合网| 超级白嫩亚洲国产第一| 亚洲精品字幕| 国产一区国产二区国产三区| 亚洲一级淫片| 日韩精品dvd| 日韩国产欧美三级| 国产精品丝袜xxxxxxx| 美女视频免费精品| 视频一区二区三区中文字幕| 欧美性感美女一区二区| 国产免费久久| 香蕉成人av| 精品一区不卡| 亚洲影院天堂中文av色| 欧美三区四区| 亚洲啊v在线免费视频| 日韩成人一级| 一区在线视频观看| 日韩国产在线| 精品免费视频| 国产福利一区二区三区在线播放| 日韩精品久久久久久| 亚洲一二av| 日本中文字幕不卡| 日韩高清一区二区|