电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

詳解JAVA 弱引用

瀏覽:5日期:2022-08-27 08:45:32

定義

弱引用是使用WeakReference創(chuàng)建的引用,弱引用也是用來描述非必需對(duì)象的,它是比軟引用更弱的引用類型。在發(fā)生GC時(shí),只要發(fā)現(xiàn)弱引用,不管系統(tǒng)堆空間是否足夠,都會(huì)將對(duì)象進(jìn)行回收。

說明

弱引用,從名字來看就很弱嘛,這種引用指向的對(duì)象,一旦在GC時(shí)被掃描到,就逃脫不了被回收的命運(yùn)。

但是,弱引用指向的對(duì)象也并不一定就馬上會(huì)被回收,如果弱引用對(duì)象較大,直接進(jìn)到了老年代,那么就可以茍且偷生到Full GC觸發(fā)前,所以弱引用對(duì)象也可能存在較長(zhǎng)的一段時(shí)間。一旦一個(gè)弱引用對(duì)象被垃圾回收器回收,便會(huì)加入到一個(gè)引用隊(duì)列中(如果有的話)。

弱引用對(duì)應(yīng)的類為WeakReference,舉個(gè)栗子:

String s = new String('Frank'); WeakReference<String> weakRef = new WeakReference<String>(s);s = null;

這里我們把s設(shè)置為null后,字符串對(duì)象便只有弱引用指向它。

弱可達(dá)

如果一個(gè)對(duì)象與GC Roots之間僅存在弱引用,則稱這個(gè)對(duì)象為弱可達(dá)(weakly reachable)對(duì)象。

注意

在垃圾回收器回收一個(gè)對(duì)象前,WeakReference類所提供的get方法會(huì)返回其引用對(duì)象的強(qiáng)引用,一旦垃圾回收器回收掉該對(duì)象之后,get方法將返回null。所以在獲取弱引用對(duì)象的代碼中,一定要判斷是否為null,以免出現(xiàn)NullPointerException異常導(dǎo)致應(yīng)用崩潰。

下面的代碼會(huì)讓s再次持有對(duì)象的強(qiáng)引用:

s = weakRef.get();

如果在weakRef包裹的對(duì)象被回收前,用強(qiáng)引用關(guān)聯(lián)該對(duì)象,那這個(gè)對(duì)象又會(huì)變成強(qiáng)可達(dá)狀態(tài)。

來看一個(gè)簡(jiǎn)單的栗子了解一下WeakReference引用的對(duì)象是何時(shí)被回收的:

public class WeakReferenceTest { private static final List<Object> TEST_DATA = new LinkedList<>(); private static final ReferenceQueue<TestClass> QUEUE = new ReferenceQueue<>(); public static void main(String[] args) { TestClass obj = new TestClass('Test'); WeakReference<TestClass> weakRef = new WeakReference<>(obj, QUEUE); //可以重新獲得OOMClass對(duì)象,并用一個(gè)強(qiáng)引用指向它 //oomObj = weakRef.get(); // 該線程不斷讀取這個(gè)弱引用,并不斷往列表里插入數(shù)據(jù),以促使系統(tǒng)早點(diǎn)進(jìn)行GC new Thread(() -> { while (true) { TEST_DATA.add(new byte[1024 * 100]); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } System.out.println(weakRef.get()); } }).start(); // 這個(gè)線程不斷讀取引用隊(duì)列,當(dāng)弱引用指向的對(duì)象唄回收時(shí),該引用就會(huì)被加入到引用隊(duì)列中 new Thread(() -> { while (true) { Reference<? extends TestClass> poll = QUEUE.poll(); if (poll != null) { System.out.println('--- 弱引用對(duì)象被jvm回收了 ---- ' + poll); System.out.println('--- 回收對(duì)象 ---- ' + poll.get()); } } }).start(); //將強(qiáng)引用指向空指針 那么此時(shí)只有一個(gè)弱引用指向TestClass對(duì)象 obj = null; try { Thread.currentThread().join(); } catch (InterruptedException e) { e.printStackTrace(); System.exit(1); } } static class TestClass { private String name; public TestClass(String name) { this.name = name; } @Override public String toString() { return 'TestClass - ' + name; } }}

設(shè)置一下虛擬機(jī)參數(shù):

-verbose:gc -Xms4m -Xmx4m -Xmn2m

運(yùn)行結(jié)果如下:

[GC (Allocation Failure) 1017K->464K(3584K), 0.0014345 secs][GC (Allocation Failure) 1483K->536K(3584K), 0.0017221 secs][GC (Allocation Failure) 1560K->648K(3584K), 0.0036572 secs]TestClass - TestTestClass - TestTestClass - Test[GC (Allocation Failure) 1621K->984K(3584K), 0.0011455 secs]--- 弱引用對(duì)象被jvm回收了 ---- java.lang.ref.WeakReference@51a947fe--- 回收對(duì)象 ---- nullnull...省略n個(gè)null和幾次GC信息[Full GC (Ergonomics) 2964K->2964K(3584K), 0.0025450 secs][Full GC (Allocation Failure) 2964K->2964K(3584K), 0.0021907 secs]java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid6860.hprof ...Heap dump file created [3912229 bytes in 0.011 secs]Exception in thread 'Thread-0' java.lang.OutOfMemoryError: Java heap spaceat weakhashmap.WeakReferenceTest.lambda$main$0(WeakReferenceTest.java:22)at weakhashmap.WeakReferenceTest$$Lambda$1/764977973.run(Unknown Source)at java.lang.Thread.run(Thread.java:748)

可以看到,其實(shí)弱引用也并不是一發(fā)生GC就被回收掉了。

應(yīng)用場(chǎng)景

如果一個(gè)對(duì)象僅僅是偶爾使用,并且希望在使用時(shí)隨時(shí)就能獲取到,但又不想影響此對(duì)象的垃圾收集,那么你應(yīng)該用 WeakReference 來引用該對(duì)象。

弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。

一般來說,很少直接使用WeakReference,而是使用WeakHashMap。在WeakHashMap中,內(nèi)部有一個(gè)引用隊(duì)列,插入的元素會(huì)被包裹成WeakReference,并加入隊(duì)列中,用來做緩存再合適不過。

在Tomcat的緩存中,其實(shí)就用到了WeakHashMap:

public final class ConcurrentCache<K,V> { private final int size; private final Map<K,V> eden; private final Map<K,V> longterm; public ConcurrentCache(int size) { this.size = size; this.eden = new ConcurrentHashMap<>(size); this.longterm = new WeakHashMap<>(size); } public V get(K k) { // 先從eden中取 V v = this.eden.get(k); if (v == null) { // 如果取不到再?gòu)膌ongterm中取 synchronized (longterm) { v = this.longterm.get(k); } // 如果取到則重新放到eden中 if (v != null) { this.eden.put(k, v); } } return v; } public void put(K k, V v) { if (this.eden.size() >= size) { // 如果eden中的元素?cái)?shù)量大于指定容量,將所有元素放到longterm中 synchronized (longterm) { this.longterm.putAll(this.eden); } this.eden.clear(); } this.eden.put(k, v); }}

這里有eden和longterm的兩個(gè)map,如果對(duì)jvm堆了解的話,可以看出tomcat在這里是使用ConcurrentHashMap和WeakHashMap做了類似分代緩存的操作。

在put方法里,在插入鍵值對(duì)時(shí),先檢查eden緩存的容量是否超出設(shè)定的大小。如果沒有則直接放入eden緩存,如果超了則鎖定longterm將eden中所有的鍵值對(duì)都放入longterm。再將eden清空并插入該鍵值對(duì)。

在get方法中,也是優(yōu)先從eden中找對(duì)應(yīng)的key,如果沒有則進(jìn)入longterm緩存中查找,找到后就加入eden緩存并返回。

經(jīng)過這樣的設(shè)計(jì),相對(duì)常用的對(duì)象都能在eden緩存中找到,不常用(有可能被銷毀的對(duì)象)的則進(jìn)入longterm緩存。而longterm的key的實(shí)際對(duì)象沒有其他引用指向它時(shí),gc就會(huì)自動(dòng)回收heap中該弱引用指向的實(shí)際對(duì)象,并將弱引用放入其引用隊(duì)列中。

弱引用與軟引用對(duì)比

弱引用與軟引用的區(qū)別在于:

只具有弱引用的對(duì)象擁有更短暫的生命周期。 被垃圾回收器回收的時(shí)機(jī)不一樣,在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。而被軟引用關(guān)聯(lián)的對(duì)象只有在內(nèi)存不足時(shí)才會(huì)被回收。 弱引用不會(huì)影響GC,而軟引用會(huì)一定程度上對(duì)GC造成影響。

相似之處:都是用來描述非必需對(duì)象的。

那么什么時(shí)候用SoftReference,什么時(shí)候用WeakReference呢?

如果緩存的對(duì)象是比較大的對(duì)象,使用頻率相對(duì)較高的對(duì)象,那么使用SoftReference會(huì)更好,因?yàn)檫@樣能讓緩存對(duì)象有更長(zhǎng)的生命周期。

如果緩存對(duì)象都是比較小的對(duì)象,使用頻率一般或者相對(duì)較低,那么使用WeakReference會(huì)更合適。

當(dāng)然,如果實(shí)在不知道選哪個(gè),一般而言,用作緩存時(shí)使用WeakHashMap都不會(huì)有太大問題。

小結(jié)

弱引用是比軟引用更弱的引用類型 弱引用不能延長(zhǎng)對(duì)象的生命周期,一旦對(duì)象只剩下弱引用,它就隨時(shí)可能會(huì)被回收 可以通過弱引用獲取對(duì)象的強(qiáng)引用 弱引用適合用作緩存

以上就是詳解 JAVA 弱引用的詳細(xì)內(nèi)容,更多關(guān)于java 弱引用的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 垃圾清运公司_环卫保洁公司_市政道路保洁公司-华富环境 | 苗木价格-苗木批发-沭阳苗木基地-沭阳花木-长之鸿园林苗木场 | 石膏基自流平砂浆厂家-高强石膏基保温隔声自流平-轻质抹灰石膏粉砂浆批发-永康市汇利建设有限公司 | 合肥礼品公司-合肥礼品定制-商务礼品定制公司-安徽柏榽商贸有限公司 | 北京网站建设-企业网站建设-建站公司-做网站-北京良言多米网络公司 | 首页-瓜尔胶系列-化工单体系列-油田压裂助剂-瓜尔胶厂家-山东广浦生物科技有限公司 | 带式过滤机厂家_价格_型号规格参数-江西核威环保科技有限公司 | 热熔胶网膜|pes热熔网膜价格|eva热熔胶膜|热熔胶膜|tpu热熔胶膜厂家-苏州惠洋胶粘制品有限公司 | 冷油器-冷油器换管改造-连云港灵动列管式冷油器生产厂家 | 山东臭氧发生器,臭氧发生器厂家-山东瑞华环保设备 | 泰国专线_泰国物流专线_广州到泰国物流公司-泰廊曼国际 | 阻垢剂,反渗透阻垢剂,缓蚀阻垢剂-山东普尼奥水处理科技有限公司 真空粉体取样阀,电动楔式闸阀,电动针型阀-耐苛尔(上海)自动化仪表有限公司 | 对辊破碎机-液压双辊式,强力双齿辊,四辊破碎机价格_巩义市金联机械设备生产厂家 | B2B网站_B2B免费发布信息网站_B2B企业贸易平台 - 企资网 | 组织研磨机-高通量组织研磨仪-实验室多样品组织研磨机-东方天净 传递窗_超净|洁净工作台_高效过滤器-传递窗厂家广州梓净公司 | 期货软件-专业期货分析软件下载-云智赢 | 抓斗式清污机|螺杆式|卷扬式启闭机|底轴驱动钢坝|污水处理闸门-方源水利机械 | 东莞螺杆空压机_永磁变频空压机_节能空压机_空压机工厂批发_深圳螺杆空压机_广州螺杆空压机_东莞空压机_空压机批发_东莞空压机工厂批发_东莞市文颖设备科技有限公司 | SPC工作站-连杆综合检具-表盘气动量仪-内孔缺陷检测仪-杭州朗多检测仪器有限公司 | 一体化污水处理设备,一体化污水设备厂家-宜兴市福源水处理设备有限公司 | 水平垂直燃烧试验仪-灼热丝试验仪-漏电起痕试验仪-针焰试验仪-塑料材料燃烧检测设备-IP防水试验机 | 纯水电导率测定仪-万用气体检测仪-低钠测定仪-米沃奇科技(北京)有限公司www.milwaukeeinst.cn 锂辉石检测仪器,水泥成分快速分析仪-湘潭宇科分析仪器有限公司 手术室净化装修-手术室净化工程公司-华锐手术室净化厂家 | 上海办公室装修公司_办公室设计_直营办公装修-羚志悦装 | 地源热泵一体机,地源热泵厂家-淄博汇能环保设备有限公司 | 油液红外光谱仪-油液监测系统-燃油嗅探仪-上海冉超光电科技有限公司 | 智慧旅游_智慧景区_微景通-智慧旅游景区解决方案提供商 | 南京技嘉环保科技有限公司-杀菌除臭剂|污水|垃圾|厕所|橡胶厂|化工厂|铸造厂除臭剂 | 细沙回收机-尾矿干排脱水筛设备-泥石分离机-建筑垃圾分拣机厂家-青州冠诚重工机械有限公司 | 针焰试验仪,灼热丝试验仪,漏电起痕试验仪,水平垂直燃烧试验仪 - 苏州亚诺天下仪器有限公司 | 拖鞋定制厂家-品牌拖鞋代加工厂-振扬实业中国高端拖鞋大型制造商 | 广东成考网-广东成人高考网| 不锈钢复合板厂家_钛钢复合板批发_铜铝复合板供应-威海泓方金属复合材料股份有限公司 | 河南卓美创业科技有限公司-河南卓美防雷公司-防雷接地-防雷工程-重庆避雷针-避雷器-防雷检测-避雷带-避雷针-避雷塔、机房防雷、古建筑防雷等-山西防雷公司 | SDG吸附剂,SDG酸气吸附剂,干式酸性气体吸收剂生产厂家,超过20年生产使用经验。 - 富莱尔环保设备公司(原名天津市武清县环保设备厂) | 工业机械三维动画制作 环保设备原理三维演示动画 自动化装配产线三维动画制作公司-南京燃动数字 聚合氯化铝_喷雾聚氯化铝_聚合氯化铝铁厂家_郑州亿升化工有限公司 | 青岛侦探调查_青岛侦探事务所_青岛调查事务所_青岛婚外情取证-青岛狄仁杰国际侦探公司 | 东莞市踏板石餐饮管理有限公司_正宗桂林米粉_正宗桂林米粉加盟_桂林米粉加盟费-东莞市棒子桂林米粉 | 深圳成考网-深圳成人高考报名网| ERP企业管理系统永久免费版_在线ERP系统_OA办公_云版软件官网 | 市政路灯_厂家-淄博信达电力科技有限公司 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 |