软引用和弱引用的区别_强、软、弱、虚引用的区别和使用
原文閱讀:
強(qiáng)、軟、弱、虛引用的區(qū)別和使用?mp.weixin.qq.comJava提供了四種級(jí)別的應(yīng)用類型:強(qiáng)引用、軟引用、弱引用及虛引用。那么這四種引用類型有什么區(qū)別呢?
首先我們通過(guò)一張圖來(lái)看看四種引用在Java中的表示:
FinalReference
由于FinalReference是包內(nèi)可見(jiàn),Finalizer是其唯一的擴(kuò)展類。在外部是無(wú)法直接使用這兩個(gè)類的,因?yàn)镕inalReference引用類型是為JVM提供的,JVM會(huì)對(duì)那些實(shí)現(xiàn)了 Object 中 finalize() 方法的類實(shí)例化一個(gè)對(duì)應(yīng)的FinalReference,提供 對(duì)象被 GC 前需要執(zhí)行 finalize 方法的對(duì)象 的機(jī)制。這里不詳細(xì)介紹。
強(qiáng)引用(StrongReference)
強(qiáng)引用在 java.lang.ref 中并沒(méi)有實(shí)際的對(duì)應(yīng)類型,但我們程序中幾乎所有的引用使用的都是強(qiáng)引用。
StringBuilder sb = new StringBuilder();上面通過(guò)在堆中創(chuàng)建實(shí)例,然后賦值給棧中局部變量 sb 的方式 就是 強(qiáng)引用。
強(qiáng)引用有如下特點(diǎn):
- 強(qiáng)引用可以直接訪問(wèn)目標(biāo)對(duì)象
- 強(qiáng)引用(存在)指向的對(duì)象任何時(shí)候都不會(huì)被回收,JVM寧愿拋出OOM異常,也不會(huì)回收。
- 強(qiáng)引用可能會(huì)導(dǎo)致內(nèi)存泄漏
注意: 為了盡量避免內(nèi)存不足的情況,我們可以在變量sb使用后通過(guò)顯示的將變量sb置為null,來(lái)加速對(duì)象的回收。
解釋: 1. 內(nèi)存溢出(out of memory) 是指 程序在申請(qǐng)內(nèi)存時(shí),沒(méi)有足夠的內(nèi)存空間供其使用,出現(xiàn) out of memory.
軟引用(SoftReference)
軟引用對(duì)應(yīng)的類為 java.lang.ref.SoftReference, 一個(gè)軟引用中的對(duì)象,不會(huì)很快被JVM回收,JVM會(huì)根據(jù)當(dāng)前堆的使用情況來(lái)判斷何時(shí)回收,當(dāng)堆的使用率超過(guò)閾值時(shí),才回去回收軟引用中的對(duì)象。
先通過(guò)一個(gè)例子來(lái)了解一下軟引用:
Object obj = new Object(); SoftReference softRef = new SoftReference<Object>(obj); //刪除強(qiáng)引用 obj = null; //調(diào)用gc System.gc(); System.out.println("gc之后的值:" + softRef.get()); // 對(duì)象依然存在軟引用也可以和一個(gè)引用隊(duì)列聯(lián)合使用,如果軟引用中的對(duì)象(obj)被回收,那么軟引用會(huì)被 JVM 加入關(guān)聯(lián)的引用隊(duì)列中。
ReferenceQueue<Object> queue = new ReferenceQueue<>(); Object obj = new Object(); SoftReference softRef = new SoftReference<Object>(obj,queue); //刪除強(qiáng)引用 obj = null; //調(diào)用gc System.gc(); System.out.println("gc之后的值: " + softRef.get()); // 對(duì)象依然存在 //申請(qǐng)較大內(nèi)存使內(nèi)存空間使用率達(dá)到閾值,強(qiáng)迫gc byte[] bytes = new byte[100 * 1024 * 1024]; //如果obj被回收,則軟引用會(huì)進(jìn)入引用隊(duì)列 Reference<?> reference = queue.remove(); if (reference != null){System.out.println("對(duì)象已被回收: "+ reference.get()); // 對(duì)象為null }引用隊(duì)列(ReferenceQueue)作用
Queue的意義在于我們?cè)谕獠靠梢詫?duì)queue中的引用進(jìn)行監(jiān)控,當(dāng)引用中的對(duì)象被回收后,我們可以對(duì)引用對(duì)象本身繼續(xù)做一些清理操作,因?yàn)槲覀円脤?duì)象(softRef)也占有一定的資源。
弱引用(WeakReference)
弱引用中的對(duì)象具有很短的聲明周期,因?yàn)樵谙到y(tǒng)GC時(shí),只要發(fā)現(xiàn)弱引用,不管堆空間是否足夠,都會(huì)將對(duì)象進(jìn)行回收。由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。
弱引用的簡(jiǎn)單使用:
Object obj = new Object(); WeakReference weakRef = new WeakReference<Object>(obj); //刪除強(qiáng)引用 obj = null; System.out.println("gc之后的值:" + weakRef.get()); // 對(duì)象依然存在 //調(diào)用gc System.gc(); System.out.println("gc之后的值:" + weakRef.get()); // 對(duì)象為null弱引用也可以和一個(gè)引用隊(duì)列聯(lián)合使用,如果弱引用中的對(duì)象(obj)被回收,那么軟引用會(huì)被 JVM 加入關(guān)聯(lián)的引用隊(duì)列中。
ReferenceQueue<Object> queue = new ReferenceQueue<>(); Object obj = new Object(); WeakReference weakRef = new WeakReference<Object>(obj,queue); //刪除強(qiáng)引用 obj = null; System.out.println("gc之后的值: " + weakRef.get()); // 對(duì)象依然存在 //調(diào)用gc System.gc(); //如果obj被回收,則軟引用會(huì)進(jìn)入引用隊(duì)列 Reference<?> reference = queue.remove(); if (reference != null){System.out.println("對(duì)象已被回收: "+ reference.get()); // 對(duì)象為null }軟引用和弱引用都非常適合保存那些可有可無(wú)的緩存數(shù)據(jù),當(dāng)內(nèi)存不足時(shí),緩存數(shù)據(jù)被回收(再通過(guò)備選方案查詢),當(dāng)內(nèi)存充足時(shí),也可以存在較長(zhǎng)時(shí)間,起到加速的作用。應(yīng)用
- WeakHashMap
當(dāng)key只有弱引用時(shí),GC發(fā)現(xiàn)后會(huì)自動(dòng)清理鍵和值,作為簡(jiǎn)單的緩存表解決方案。
- ThreadLocal
ThreadLocal.ThreadLocalMap.Entry 繼承了弱引用,key為當(dāng)前線程實(shí)例,和WeakHashMap基本相同。
虛引用(PhantomReference)
虛引用 就是 形同虛設(shè) ,它并不能決定 對(duì)象的生命周期。任何時(shí)候這個(gè)只有虛引用的對(duì)象都有可能被回收。因此,虛引用主要用來(lái)跟蹤對(duì)象的回收,清理被銷毀對(duì)象的相關(guān)資源。PhantomReference的 get() 方法永遠(yuǎn)返回null ,而且只提供了與引用隊(duì)列同用的構(gòu)造函數(shù)。所以虛引用必須和引用隊(duì)列一同使用。
Map<Object, String> map = new HashMap<>(); ReferenceQueue<Object> queue = new ReferenceQueue<>(); Object obj = new Object(); PhantomReference phantomRef = new PhantomReference<Object>(obj,queue); map.put(obj,"obj val"); new CheckRefQueue(queue,map).start(); //刪除強(qiáng)引用 obj = null; Thread.sleep(1000); int i = 1; while (true){System.out.println("第"+i+"次gc");System.gc();Thread.sleep(1000); } public class CheckRefQueue extends Thread {private ReferenceQueue queue;private Map<Object, String> map;public CheckRefQueue(ReferenceQueue queue, Map<Object, String> map) {this.queue = queue;this.map = map;}@Overridepublic void run() {// 等待,直到對(duì)象唄回收Reference reference = queue.remove();// 釋放引用對(duì)象的引用map.remove(reference.get());} }總結(jié)
總結(jié)
以上是生活随笔為你收集整理的软引用和弱引用的区别_强、软、弱、虚引用的区别和使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【LeetCode笔记】剑指 Offer
- 下一篇: 产生复选框的html,html根据复选框