“这是我参与8月更文挑战的第12天,活动详情查看:8月更文挑战”
🔴 引言 ☀️
昨天我们讲到了垃圾回收要面对的三个问题即:回收哪块,如何回收还有什么时候回收,今天我们就来聊聊对象检查,我们知道狼是世界上最凶险最狡猾的动物,尤其是群狼,老虎见了都要怕三分,那狼在猎杀羊的时候也不是随时猎杀,它们很有耐性,也懂得侦察羊的状态,垃圾回收又何尝不是如此呢?我们在进行垃圾回收之前,首先得知道一些垃圾检测算法,一起来学习一下吧。
🔴引用计数法☀️
我们对引用计数法的描述是这样的:我们在对象中添加一个引用计数器,当对象被引用时计数加1,当引用失效时,计数减1,任何时刻只要计数器为0那就是不可用的对象(好像定时炸弹💣有木有)。
不得不承认引用计数法(ReferenceCounting)简单而且高效,是绝大多数情况都适用的算法,但对于java语言来说,对象之间的依赖关系复杂多变,引用计数法就不是我们最好的选择,比如我们绝大多数情况下都会遇到的循环依赖的问题,循环依赖中,引用计数器无法清零,因此也就无法回收了。
🔴可达性分析算法☀️
由于引用计数的天然缺陷,致使我们不得不寻找其它的算法,于是就出现了可达性分析法(Reachability Analysis),可达性分析顾名思义就是可以到达的地方,从哪出发啊?从“GC Roots”出发,到哪去啊?哈哈不用管,只要能在根对象的链上就行,就是说:从根对象出发,一直走,不管怎么走,都能到达的地方证明对象可达,反之则不可达。
🔵GCRoots🔵
前面提到了“GC Roots”是根对象,那根对象既然是对象肯定是有类型的,那有哪些呢?大概有这么几种,我给大家罗列了一下(快夸夸我😄):
- 在虚拟机栈中引用的对象
- 方法区中静态属性引用的变量
- 方法区中常量引用的对象
- 本地方法栈中
JNI引用的对象 java虚拟机内部的引用- 所有被同步锁持有的对象
- 反映
Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、代码缓存等。
除了固定的根对象,有没有不固定的?答案是当然了!用户可以根据所选的垃圾收集器以及回收的区域临时的加入一些根对象进去,如果只针对java堆的某一块区域进行垃圾回收,那就需要考虑虚拟机自己实现的具体细节,来针对性的加入一些关联区域的对象到GC Roots集合中,才能保证可达性分析的正确性。
🔵对象引用🔵
无论是引用计数法还是可达性分析法,都与对象引用离不开关系。在JDK1.2之前,对于对象引用的定义还是很笼统,简单来说要么就是引用,要么就是没有引用,比如你看美女就是色狼,你不看就是君子,这太扯淡了。
于是,1.2之后,Java把引用进一步细分为4种:
- 强引用(
Strongly-Reference) - 弱引用(
Weak-Reference) - 软引用(
Soft-Reference) - 虚引用(
Phantom-Reference)
引用强度:Strongly>Soft>Weak>Phantom
🔷强引用🔷
我们的传统引用就是强引用,简单来说就是最普通的赋值,Object obj = new Objet();无论任何情况下,只要强引用关系存在,就不是垃圾回收的对象。
🔷软引用🔷
软引用就是还有用但非必须的对象,就是在系统发生内存溢出之前,把软引用进行第二波垃圾回收,如果还没有足够的内存就会抛出异常。
🔷弱引用🔷
弱引用还要比软引用更弱一些,当垃圾收集发生时,不管内存是否足够都会清除被弱引用关联的对象。
🔷虚引用🔷
虚引用就更弱了,设置虚引用的唯一目的就是能在这个对象被垃圾回收时,能得到一个系统通知。
💭题外话
成吉思汗就那点骑兵,咋就能打败大金国百万大军?打败几十个国家?光靠狼的狠劲还不成,还得靠狼的耐性。再多再强的敌人也有犯迷糊的时候。大马犯迷糊,小狼也能把它咬死。没耐性就不是狼,不是猎人,不是成吉思汗。如果说要弄明白狼(垃圾回收),弄明白成吉思汗(java虚拟机),你先耐着性子好好地学吧。