一次性把Java的四种引用说清楚!
云栖号资讯:【点击查看更多行业资讯】
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!
前几天在CodeReview的时候,看到了一个用WeakHashMap的代码,进而聊到了WeakReference,再聊到Java四种引用类型。
回想了一下,上次学习Java的强软弱虚四种引用类型,还是在准备面试的时候。平时用得不多,一下子竟然想不清楚它们的区别,只记得它们的强度依次递减。
下来又看了一下这方面的文章,今天好好把它们理清楚。
四种引用的区别
其实四种引用的区别在于GC的时候,对它们的处理不同。用一句话来概括,就是:如果一个对象GC Root可达,强引用不会被回收,软引用在内存不足时会被回收,弱引用在这个对象第一次GC会被回收。
如果GC Root不可达,那不论什么引用,都会被回收
虚引用比较特殊,等于没有引用,不会影响对象的生命周期,但可以在对象被收集器回收时收到一个系统通知。
下面结合案例分别来讲一下四种引用在面对GC时的表现以及它们的常见用途。先设置一下JVM的参数:
强引用
这就是我们平时最常使用的引用。只要GC的时候这个对象GC Root可达,它就不会被回收。如果JVM内存不够了,直接抛出OOM。比如下面这段代码就会抛出OutOfMemoryError
软引用
软引用,当GC的时候,如果GC Root可达,如果内存足够,就不会被回收;如果内存不够用,会被回收。将上面的例子改成软引用,就不会被OOM:
我们把程序改造一下,打印出GC后的前后的差别:
会发现,打印出的日志,GC前都是有值的,而GC后,会有一些是null,代表它们已经被回收。
而我们设置的堆最大为20M,如果把循环次数改成15,就会发现打印出的日志,GC后没有为null的。但通过-verbose:gc -XX:+PrintGCDetails参数能发现,JVM还是进行了几次GC的,只是由于内存还够用,所以没有回收。
所以软引用的常见用途就呼之欲出了:缓存。尤其是那种希望这个缓存能够持续时间长一点的。
弱引用
软引用,只要这个对象发生GC,就会被回收。
把上面的代码改成软引用,会发现打印出的日志,GC后全部为null。
所以弱引用也适合用来做缓存,不过由于它是只要发生GC就会被回收,所以存活的时间比软引用短得多,通常用于做一些非常临时的缓存。
我们知道,WeakHashMap内部是通过弱引用来管理entry的。它的键是“弱键”,所以在GC时,它对应的键值对也会从Map中删除。
- Tomcat中有一个ConcurrentCache,用到了WeakHashMap,结合ConcurrentHashMap,实现了一个线程安全的缓存,感兴趣的同学可以研究一下源码,代码非常精简,加上所有注释,只有短短59行。
ThreadLocal中的静态内部类ThreadLocalMap里面的entry是一个WeakReference的继承类。
- 使用弱引用,使得ThreadLocalMap知道ThreadLocal对象是否已经失效,一旦该对象失效,也就是成为垃圾,那么它所操控的Map里的数据也就没有用处了,因为外界再也无法访问,进而决定擦除Map中相关的值对象,Entry对象的引用,来保证Map总是保持尽可能的小。
虚引用
虚引用的设计和上面三种引用有些不同,它并不影响GC,而是为了在对象被GC时,能够收到一个系统通知。
那它是怎么被通知的呢?虚引用必须要配合ReferenceQueue,当GC准备回收一个对象,如果发现它还有虚引用,就会在回收之前,把这个虚引用加入到与之关联的ReferenceQueue中。
那NIO是如何利用虚引用来管理内存的呢?
DirectBuffer直接从Java堆之外申请一块内存, 这块内存是不直接受JVM GC管理的, 也就是说在GC算法中并不会直接操作这块内存. 这块内存的GC是由于DirectBuffer在Java堆中的对象被GC后, 通过一个通知机制, 而将其清理掉的。
DirectBuffer内部有一个Cleaner。这个Cleaner是PhantomReference的子类。当DirectBuffer对象被回收之后, 就会通知到PhantomReference。然后由ReferenceHandler调用tryHandlePending()方法进行pending处理. 如果pending不为空, 说明DirectBuffer被回收了, 就可以调用Cleaner的clean()进行回收了。
上面这个方法的代码在Reference类里面,有兴趣的同学可以去看一下那个方法的源码。
总结
以上就是Java中四种引用的区别。一般来说,强引用我们都知道,虚引用很少用到。而软引用和弱引用的区别在于回收的时机:软引用GC时,发现内存不够才回收,弱引用只要一GC就会回收。
【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK
原文发布时间:2020-05-19
本文作者:编了个程
本文来自:“掘金”,了解相关信息可以关注“掘金”
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
六问数据中台!你想知道的都在这了!
云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 数据中台、相信这四个字大家一定不陌生。因为在2019年、数据中台可谓是最火的概念之一,很多大公司都在布局自己的数据中台。 那么数据中台到底是什么?它和我们熟知的数据平台有啥区别?它为什么会这么火、能给企业带来什么价值呢?数据中台整体架构和全景图又是什么呢? 笔者有幸参与了公司数据中台从0到N的建设,计划从概念到落地,把中台那些事跟您说透,与您一起分享学习。 第一问:数据中台是什么 先不说那些官方的抽象的概念了,我想用我自己的大白话去说数据中台的概念。 那就是如果把前台比作赚钱的。后台比作支持的。那么中台呢就是支持加速赚钱的。 这个比喻我觉得还是很形象的,中台呢它实质就是前台和后台的一个桥梁,并且它能在这当中起到很好的加速效果。这里的加速,可以是效率上的提高,可以是协作上的共赢。 举个例子,比如前台业务人员日常要分析广告投放、在哪个平台投放效益最好呢?抖音还是头条呢?这直接涉及到公司的money了。 前台人员要分析这个肯定要有数据吧、就会向后台人员要数据:我需要哪些表你要帮我同步过来数仓里...
- 下一篇
Java的泛型详解(一)
Java的泛型详解(一) 编写的代码可以被不同类型的对象所重用。因为上面的一个优点,泛型也可以减少代码的编写。1|2泛型的使用简单泛型类public class Pair { private T first; private T second; public Pair() { first = null; second = null; } public Pair(T first, T second){ this.first = first; this.second = second; } public T getFirst(){ return first; } public T getSecond(){ return second; } public void setFirst(T first) { this.first = first; } public void setSecond(T second) { this.second = second; } }上面例子可以看出泛型变量为T;用尖括号(<>)括起来,并放在类名后面;泛型还可以定义多个类型变量比如上面的例子 fir...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS关闭SELinux安全模块
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Hadoop3单机部署,实现最简伪集群
- Docker使用Oracle官方镜像安装(12C,18C,19C)