欢迎大家来到IT世界,在知识的湖畔探索吧!
目录
- 前言
- 垃圾回收
- 引用
- 强引用
- 软引用
- 弱引用
- 虚引用
- 总结
前言
很多小伙伴们都提到过去面试的时候,经常有面试官问到知道强引用、软引用、弱引用、虚引用吗?他们各自的特点是什么?很多老司机对这些也不是太了解,今天老顾就来介绍一下。
垃圾回收
我们都知道java的JVM有垃圾回收机制,GC判断堆中的对象实例或数据是不是垃圾的方法有引用计数法和可达性算法两种。
无论是通过引用计数算法判断对象的引用数量,还是通过根搜索算法判断对象的引用链是否可达,判定对象是否存活都与“引用”有关,即是否要把这些对象视为垃圾回收掉
引用
我们先来说说什么是引用?Java中的引用,类似 C 语言中的指针。初学 Java时,我们就知道 Java数据类型分两大类,基本类型和引用类型。
基本类型:编程语言中内置的最小粒度的数据类型。它包括四大类八种类型:
4种整数类型:byte、short、int、long
2种浮点数类型:float、double
1种字符类型:char
1种布尔类型:boolean
引用类型:引用类型指向一个对象,不是原始值,指向对象的变量是引用变量。
在Java里,除了基本类型,其他类型都属于引用类型,它主要包括:类、接口、数组、枚据、注解
如:Person person = new Person(“张三”);
这里的person就是指向Person实例“张三”的引用,我们一般都是通过person来操作“张三”实例。
在 JDK 1.2 之前,Java 中的引用的定义很简单,一个对象只有被引用或者没有被引用两种状态。也就是代表了要么被回收,要么继续保持着,没有中间的缓存场景。
在 JDK 1.2 之后,Java 对引用的概念进行了扩充,将引用分为
强引用(Strong Reference)
软引用(Soft Reference)
弱引用(Weak Reference)
虚引用(Phantom Reference)
这四种引用强度依次逐渐减弱。
Java 中引入四种引用的目的是让程序自己决定对象的生命周期,JVM 是通过垃圾回收器对这四种引用做不同的处理,来实现对象生命周期的改变。
强引用
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用对象来解决内存不足的问题。
如:Object obj = new Object();这种就是强引用;我们再看看是否会被垃圾回收
执行结果
null
java.lang.Object@17c68925
欢迎大家来到IT世界,在知识的湖畔探索吧!
上面代码尽管 o1已经被回收,但是o2强引用o1,一直存在,所以不会被GC回收;
如果我们一直循环创建,超出了分配的堆内存,即使代码中我们调用了System.gc(),但也不会回收对象,就会导致OutOfMemoryError内存溢出错误。
软引用
软引用是用来描述一些还有用但并非必须的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行第二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。
欢迎大家来到IT世界,在知识的湖畔探索吧!使用软引用的方式是SoftReference
在执行上面代码的时候,配置一下vm参数,这样可以看到效果。
因为上面的代码,虽然我们代码主动做了System.gc,但是s1软引用是没有被回收的
执行结果
[B@17c68925
[B@17c68925
null
[B@17c68925
那我们再来看一个场景,如果内存不足的情况,会是什么情况
上面的代码在后面我们又创建了一个大对象,虽然没有代码中没有主动的gc,但是jvm也会主动触发垃圾回收,这个时候我们发现软引用也被回收了。
执行结果
欢迎大家来到IT世界,在知识的湖畔探索吧![B@17c68925
[B@17c68925
null
null
软引用通常用在对内存敏感的程序中,比如高速缓存就有用到软引用,内存够用的时候就保留,不够用就回收。
我们经常用到的mybatis中,类SoftCache就用到了软引用
软引用非常适合缓存的场景,我们在使用缓存时有一个原则,如果缓存中有就从缓存获取,如果没有就从数据库中获取,缓存的存在是为了加快计算速度,如果因为缓存导致了内存不足进而整个程序崩溃,那就得不偿失了。
弱引用
弱引用也是用来描述非必须对象的,他的强度比软引用更弱一些,被弱引用关联的对象,在垃圾回收时,如果这个对象只被弱引用关联(没有任何强引用关联他),那么这个对象就会被回收。
简单的说明就是,只要垃圾回收,不管内存够不够用,弱引用都会被回收。
使用弱引用的方式是类WeakReference
上面代码主动gc后,弱引用相关的就直接会被回收。
弱引用的使用场景是什么呢?
举个例子
Size of Map: 1
上面我们发现,把key即使设置为null,但还是没有被回收。
那我们看看弱引用方式,有个WeakHashMap
执行结果
绝大多数在设置key为null后,立即system.gc()后,aMap.size()就为0了,代表被垃圾回收了
Took 0 calls to System.gc() to result in weakHashMap size of : 0
但有时候会出现第一次gc没有垃圾回收掉,要到while里面再system.gc(),aMap.size才为0
while system gc count : 1
Took 1 calls to System.gc() to result in weakHashMap size of : 0
为什么会出现这个情况?
在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。
不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象
虚引用
虚引用也称为“幽灵引用”或者“幻影引用”,它是最弱的一种引用关系;我们可以理解为一个引用标识。
如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收,它不能单独使用也不能通过它访问对象,虚引用必须和引用队列(RefenenceQueue)联合使用。
虚引用的主要作用是跟踪对象垃圾回收的状态。仅仅是提供了一种确保对象被 finalize 以后,做某些事情的机制。
PhantomReference 的 get 方法总是返回 null,因此无法访问对应的引用对象。其意义在于说明一个对象已经进入 finalization 阶段,可以被 GC 回收,用来实现比 finalization 机制更灵活的回收操作。
换句话说,设置虚引用的唯一目的,就是在这个对象被回收器回收的时候收到一个系统通知或者后续添加进一步的处理
举个例子
上面的代码,有个引用队列对象,它起到的作用就是,在虚引用对象被垃圾回收时,会把虚引用对象加入到引用队列ReferenceQueue中
执行结果
o1:java.lang.Object@17c68925
referenceQueue:null
phantomReference:null
=================
o1:null
referenceQueue:java.lang.ref.PhantomReference@7e0ea639
phantomReference:null
虚引用可以理解为一个引用标示,起到垃圾回收事件回调的作用
总结
我们整理一下,4种引用方式,如下:
今天就分享到这里,谢谢!!!
推荐阅读
了解JAVA中的SPI机制,以及数据库驱动插件,这一篇就够了
企业实战之阿里druid统一监控方案,你了解吗?
千人千面精准推荐之大白话讲解协同算法(一),看这篇就够了
企业实战之分布式锁方案一步步的演变
你了解滑动时间窗口吗?Sentinel核心源码剖析
Sentinel全局Feign默认熔断降级策略的思考
你所不知道的头部参数传递的坑,来吧!抓紧出坑
5分钟让你理解K8S必备架构概念,以及网络模型(一)
5分钟让你理解K8S必备架构概念,以及网络模型(二)
5分钟让你理解K8S必备架构概念,以及网络模型(三)
大厂如何基于binlog解决多机房同步mysql数据(一)?
大厂如何基于binlog解决多机房同步mysql数据(二)?
基于binlog的canal组件有哪些使用场景(三)?
基于binlog日志之canal企业应用及高可用原理(四)?
可用于大型应用的微服务生态灰度发布如何实现?
一线大厂级别公共Redis集群监控,细化到每个项目实例
Sharding-jdbc的实战入门之水平分表(一)
Sharding-Jdbc之水平分库和读写分离(二)
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/36439.html