Java中四种引用详解
目录
- 强引用
- 软引用
- 弱引用
- 虚引用
- 总结
强引用 被强引用的对象,不会被垃圾回收器回收,JVM 宁愿抛出 OOM 也不会去回收被强引用的对象;
M m = new M();
软引用 当堆空间够用时,GC 不会对软引用的对象进行回收,当堆空间不足以分配新的空间时,触发 GC 就会对这部分对象进行回收,通常用在缓存等领域。将缓存对象使用软引用,空间不足的时候释放这部分空间,需要再次使用的时候,重新从 DB 中加载即可。
另外软引用可以配合队列(
ReferenceQueue
) 来使用,如果软引用引用的对象被垃圾回收,JVM 会把软引用加入到与之关联的引用队列中。/** * 软引用:一般用在缓存,只要空间不足,GC 跑起来就会回收它 * 运行参数 -Xmx200m -XX:+PrintGC * Created by etfox on 2021/03/01 17:06 **/public class TestSoftReference {public static void main(String[] ags) throws InterruptedException {//100M的缓存数据byte[] cacheData = https://www.it610.com/article/new byte[100 * 1024 * 1024]; //将缓存数据用软引用持有SoftReferencecacheRef = new SoftReference<>(cacheData); //将缓存数据的强引用去除cacheData = https://www.it610.com/article/null; System.out.println("第一次GC前" + cacheData); System.out.println("第一次GC前" + cacheRef.get()); //进行一次GC后查看对象的回收情况System.gc(); //等待GCThread.sleep(500); System.out.println("第一次GC后" + cacheData); System.out.println("第一次GC后" + cacheRef.get()); //在分配一个120M的对象,看看缓存对象的回收情况byte[] newData = https://www.it610.com/article/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
弱引用 弱引用的引用对象在每次 GC 时,不管当前堆内存大小,都会将这个对象清除。如果此对象偶尔使用,并且希望需要用到的时候可以获取到,但是又不希望影响这个对象的回收,就可以使用弱引用来描述对象。
当然弱引用也可以结合事件队列使用。
/** * 弱引用:如果对象时偶尔使用,并且希望使用的时候就能获取到(get),但是又不想影响此对象的垃圾收集 * 可以引入队列 * Created by etfox on 2021/03/01 17:59 **/public class TestWeakReference {public static void main(String[] args) throws InterruptedException {//100M的缓存数据byte[] cacheData = https://www.it610.com/article/new byte[100 * 1024 * 1024]; //将缓存数据用软引用持有WeakReferencecacheRef = new WeakReference<>(cacheData); System.out.println("第一次GC前" + cacheData); System.out.println("第一次GC前" + cacheRef.get()); //进行一次GC后查看对象的回收情况System.gc(); //等待GCThread.sleep(500); System.out.println("第一次GC后" + cacheData); System.out.println("第一次GC后" + cacheRef.get()); //将缓存数据的强引用去除cacheData = https://www.it610.com/article/null; System.gc(); //等待GCThread.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
虚引用 虚引用,顾名思义是虚幻的,虚引用的对象并不能在 get 的时候获取到它。它也在我们日常开发中没有适用的场景,它的主要作用是用来跟踪一个对象的生命周期 (通常来说是直接内存 [JDK1.5 Java 中除了由 JVM 管理的空间,还可以在内存中直接分配对象]中的对象),一般使用在 JVM 的开发中,主要用来管理直接内存,因为直接内存通常 GC 无法管理这一块内存(C++ delete 完事),需要特殊处理。
例如 NIO 的 ByteBuffer.allocateDirect(1024); 分配内存到直接内存空间中,通常来说从网卡中读取的数据,由操作系统读取到直接内存中,在需要使用的时候,需要拷贝到 JVM 堆空间中,如果不使用 allocateDirect 就需要一个拷贝的过程,这是非常消耗时间的,
// |-- ---| | --------| |------------|使用直接存内存省略了拷贝的过程,俗称 nio 的 zero copy,但是直接内存中的对象在不需要使用的时候无法通过正常 GC 过程去管理这一块空间,所以用到了虚引用,
// | 网卡 | ==> | 直接内存 | == copy ==> | JVM 堆空间 |
// |--- --| | ------- | |------------|
解释:
虚引用需要配合一个事件队列一起使用,JVM GC 的时候并不是说把虚引用的引用清理掉完事,而是说会把虚引用的引用放到事件队列当中,垃圾回收线程会时不时的去检查这个事件队列,看一下引用的回收过程需不需要做一些后续善后处理(例如清理直接内存中的对象,这玩意儿由实现人去弄)这就是虚引用的作用和含义了。
/** * 虚引用:可以通过队列跟踪一个对象的生命周期,一般在写 JVM 相关的时候才会用到虚引用,主要用来管理直接内存(C++ delete 一下子完事) * -Xmx20m -XX:+PrintGC * Created by etfox on 2021/03/03 12:14 **/public class TestPhantomReference {private static final List
总结
【Java中四种引用详解】本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- 热闹中的孤独
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- Shell-Bash变量与运算符
- JS中的各种宽高度定义及其应用
- 2021-02-17|2021-02-17 小儿按摩膻中穴-舒缓咳嗽
- 深入理解Go之generate
- 异地恋中,逐渐适应一个人到底意味着什么()
- 我眼中的佛系经纪人
- 《魔法科高中的劣等生》第26卷(Invasion篇)发售
- “成长”读书社群招募