Java 对象的四种引用-强软弱虚
admin
2024-02-29 11:50:52
0

Java 中对象的引用分为四种,可以让我们更好的保证程序运行时足够的内存,这也是面试时经常问到的题目,在此记录一下。

一、强引用

最开始学习的 Java 变量的声明方式其实就是强引用,这是最常用、最普遍的引用。

String str = new String("Hello World");

这其实就是强引用。如果一个对象具有强引用,GC 绝不会回收它。当内存不够用时,JVM 宁愿抛出 OOM 异常也不会回收强引用对象。只有显式将强引用置为 null 才可以释放对象。

如下代码,最终会抛出异常 Exception in thread "main" java.lang.OutOfMemoryError: Java heap space(自己测试时为了更快看到效果可以将 JVM 堆内存改小一下,如何设置可自行百度)。

package com.qinshou.resume.reference;import java.util.ArrayList;
import java.util.List;public class ReferenceDemo {private static boolean sStart = true;public static void main(String[] args) {strongReference();}public static void strongReference() {String str = new String("Hello World");List list = new ArrayList<>();int index = 0;long startTime = System.currentTimeMillis();while (sStart) {list.add(new String("Hello World " + (index++)));System.out.println("执行时间--->" + (System.currentTimeMillis() - startTime));try {Thread.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}

二、软引用

对于软引用,如果内存空间足够,GC 就不会回收它,如果内存不足了才会回收。

Java 中所有的引用都是 Reference 的子类,它是个抽象类,软引用对应的实现类是 SoftReference。我们可以将一个对象作为参数来创建 SoftReference 对象,这样就可以将这个对象的引用指定为软引用了。然后可以通过 SoftReference 对象的 get() 方法来获取传入的对象。

String str = new String("Hello World");
Reference softReference = new SoftReference<>(str);
System.out.println("softReference.get--->" + softReference.get());

软引用、弱引用、虚引用都可以搭配 ReferenceQueue 来使用,当所引用的对象被 GC 回收时,虚拟机会把这个引用加入到这个引用队列中。我们可以利用这个 ReferenceQueue 来跟踪对象的生命周期,可以通过 poll() 或者 remove() 方法来获取被回收的引用,这两个方法的区别是一个阻塞,一个非阻塞。因为从队列中获取到的引用是被回收的引用,所以调用它的 get() 方法得到的永远是 null。

package com.qinshou.resume.reference;import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.List;public class ReferenceDemo {private static boolean sStart = true;public static void main(String[] args) {softReference();}public static void softReference() {String str = new String("Hello World");Reference softReference = new SoftReference<>(str);System.out.println("softReference.get--->" + softReference.get());ReferenceQueue referenceQueue = new ReferenceQueue<>();List> list = new ArrayList<>();new Thread(new Runnable() {@Overridepublic void run() {try {// poll() 方法会从队列中取去第一个引用,没有的话直接返回 nullReference reference = referenceQueue.poll();System.out.println("reference--->" + reference);// remove() 方法会从队列中取去第一个引用,没有的话会阻塞当前线程,直到有被回收的引用reference = referenceQueue.remove();System.out.println("reference--->" + reference);sStart = false;// 从队列中获取的引用,调用 get() 方法获取真实对象的时候永远为 null,因为已经被回收掉了Object object = reference.get();System.out.println("object--->" + object);} catch (InterruptedException e) {e.printStackTrace();}}}).start();int index = 0;long startTime = System.currentTimeMillis();while (sStart) {list.add(new SoftReference<>(new String("Hello World " + (index++)), referenceQueue));System.out.println("执行时间--->" + (System.currentTimeMillis() - startTime));try {Thread.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}

三、弱引用

弱引用跟软引用的区别的在于,软引用只会在内存空间不足时 GC 才会回收,而弱引用的话只要 GC 扫描到该引用所在内存区域,无论内存空间是否充足都会回收。

package com.qinshou.resume.reference;import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;public class ReferenceDemo {private static boolean sStart = true;public static void main(String[] args) {weakReference();}public static void weakReference() {String str = new String("Hello World");Reference weakReference = new WeakReference<>(str);System.out.println("weakReference.get--->" + weakReference.get());ReferenceQueue referenceQueue = new ReferenceQueue<>();List> list = new ArrayList<>();new Thread(new Runnable() {@Overridepublic void run() {try {Reference reference = referenceQueue.remove();sStart = false;} catch (InterruptedException e) {e.printStackTrace();}}}).start();int index = 0;long startTime = System.currentTimeMillis();while (sStart) {list.add(new WeakReference<>(new String("Hello World " + (index++)), referenceQueue));System.out.println("执行时间--->" + (System.currentTimeMillis() - startTime));try {Thread.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}

上述代码的 while 循环,退出得会比使用软引用时要快很多。在 Android 中,使用弱引用是防止内存泄漏的一个常见手段。

四、虚引用

虚引用又称幽灵引用、影子引用,它无法通过 get 方法获取到实例,如果一个对象仅持有虚引用,那它跟没有引用一样。虚引用主要跟 ReferenceQueue 一起搭配使用,用来跟踪对象被 GC 回收。

package com.qinshou.resume.reference;import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.List;public class ReferenceDemo {private static boolean sStart = true;public static void main(String[] args) {phantomReference();}public static void phantomReference() {String str = new String("Hello World");PhantomReference phantomReference = new PhantomReference<>(str, null);System.out.println("phantomReference.get--->" + phantomReference.get());ReferenceQueue referenceQueue = new ReferenceQueue<>();List> list = new ArrayList<>();new Thread(new Runnable() {@Overridepublic void run() {try {Reference reference = referenceQueue.remove();sStart = false;} catch (InterruptedException e) {e.printStackTrace();}}}).start();int index = 0;long startTime = System.currentTimeMillis();while (sStart) {list.add(new PhantomReference<>(new String("Hello World " + (index++)), referenceQueue));System.out.println("执行时间--->" + (System.currentTimeMillis() - startTime));try {Thread.sleep(1);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
}

五、总结

合理使用 Java 提供的各种引用,可以更好的控制程序内存,优化我们的程序,减少 OOM 的风险。比如在设计一些缓存机制的时候,将缓存对象设置为软引用或虚引用,既可以实现高速缓存,又能避免一些内存问题。

相关内容

热门资讯

贵州酸汤鱼:红酸汤发酵半年,木... 贵州酸汤鱼是黔菜中的璀璨明珠,其灵魂在于历经半年发酵的红酸汤与点睛之笔的木姜子油。本文将深入探寻这道...
51岁男子疑坐1米高栏杆不慎坠... 8月2日,辽宁丹东凤城市凤凰山景区有游客不慎坠落,景区组织专业救援力量,最终在老牛背景点前面一块山地...
喜洲破酥粑粑:现烤酥皮簌簌掉渣... 喜洲破酥粑粑是云南大理喜洲古镇的标志性美食,以现烤时酥皮簌簌掉渣的独特口感和甜咸双拼的经典口味闻名。...
云南普洱暑期旅游升温 茶咖融合... 中新网普洱8月4日电 (徐晓芳 艾奕含 王晓东)正值暑期,云南省普洱市“茶旅”“咖旅”热度不断升温,...
〔读城〕尽快将“预制菜”更名为... 文 / 李后强 中共四川省委四川省人民政府决策咨询委员会副主任、成都市社会科学界联合会主席、四川省社...
新加坡旅行社接待方案分享|中企... 在跨境激励、出海布局成为越来越多中国企业关注重点的今天,东南亚城市中,新加坡因其优越的地理位置、成熟...
浙江行吟之温岭、雁荡|刘夏明 建议创作景点: 花山九老祠小楼基地挂牌,林厝(非遗和渔文化),长屿硐天,利欧集团,其它景点随意发挥。...
旅游四川·平武|白马藏乡避暑见... 八月的川蜀大地,暑气蒸腾。日前,从成都驱车,经过几个小时,终于抵达四川平武县白马藏族乡场镇。这里以其...
城市24小时 | 留住“过客”... 每经记者:杨欢 每经编辑:刘艳美 图片来源:每经记者 杨欢 摄 日前,云南省委人才工作领导小组印发...
原创 厨... 刚毕业独居那会儿,我的厨艺水平仅限于"煮泡面加蛋"。 直到被外卖吃空了钱包,才下定决心要学做饭。 ...
尽快将“预制菜”更名为“预制食... 将“预制菜”更名为“预制食材”,不仅是术语的修正,更是对产业本质的重新定位。这一调整有助于消除公众对...
白敬亭片场助理爆料其爱吃零食小... 白敬亭,这位在娱乐圈熠熠生辉的男演员,凭借着精湛的演技和帅气的外表收获了无数粉丝的喜爱。而近日,其片...
原创 后... 北海银滩景区部分海域出现不明液体,官方通报:高度重视,正在调查 哎,这北海银滩海域出现不明液体,...
当演唱会遇上旅行社:一次特别定... “我不是来旅游的,我是来见TA的。” 这是越来越多年轻人在计划海外旅行时的真实想法。不同于传统意义的...