糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > 深入理解Java虚拟机(三)——对象已死吗

深入理解Java虚拟机(三)——对象已死吗

时间:2023-10-10 17:52:05

相关推荐

深入理解Java虚拟机(三)——对象已死吗

垃圾收集器(对象回收条件,四大引用,对象的自我拯救)

概述
前面我l们了解到了Java内存运行时区域的各个部分,其中程序计数器,虚拟机栈,本地方法栈这三个区域随线程而生,随线程而灭。因此这几个区域的内存分配和回收都具有确定性,因为方法结束或者线程结束时,内存就自然跟着回收了,所以这几个区域不需要过多的考虑回收的问题。而堆和方法区则不太一样,一个接口中的多个实现类需要的内存不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期间才能知道会创建哪些对象,这部分内存的分配和回收都是动态的,垃圾回收器所关注的就是这部分的内存。

1.判断对象是否回收

(1)引用计数算法

基本思想

给对象添加一个引用计数器,每当有一个地方引用它时,技术器加1,当引用失效时,计数器减1,任何时刻计数器为0的对象就是不可能再被使用的,这个对象就是需要被回收的。

优缺点

引用计数算法的实现简单,判定效率也很高,大部分情况在它都是一个不错的算法。

但是一些主流的Java虚拟机中却没有使用这种算法,主要是因为它无法解决对象之间循环相互引用的问题。

package com.westmo.demo1;public class MyDemo1 {public Object instance=null;public static void main(String[] args) {test();}public static void test() {MyDemo1 myDemo1 = new MyDemo1();MyDemo1 myDemo2 = new MyDemo1();myDemo1.instance=myDemo2;myDemo2.instance=myDemo1;myDemo1=null;myDemo2=null;}}/上面的代码中,test()方法中,由程序的最后可以看出这两个对象已没有引用,应该被GC收集器回收,但是这两个对象又互相引用着对方,所以他们的引用计数都不为0,引用计数算法就不行,后面的这种算法就不会存在这样的问题。

(2)可达性算法

(1)基本思想

这个算法的思想就是通过一系列“GC Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则该对象就是不可达的,这个对象就会被判定为可回收对象,所走过的路径称为引用链。简而言之,就是以一个对象为起点,看能走到那个对象,走不到的对象就是不可达的。所以,这个起点就很重要。

如上图中,以GC Roots对象为起点,根本就无法走到Object5,Object6,Object7这三个对象,所以这三个对象就会被判定为可回收的对象。

(2)可作为GC Roots的对象

- 虚拟机栈中引用的对象(栈帧中的本地变量表) - 方法区中类静态属性引用的对象- 方法区中常量引用的对象- 本地方法栈中引用的对象

2.引用

概述

通过前面的学习我们知道,无论是通过引用计数算法设置计数器判断对象的引用还是通过可达性算法判断对象的引用链是否可达,都涉及到了引用这个问题。简而言之,如果一个变量是一个类类型,那么这个变量就是一个引用。这种定义很纯粹,这样的话,一个对象就只有被引用和没被引用两种状态。我们希望能描述这样一种对象,当内存空间足够时,则白柳这些对象,当内存空间不够时,则抛弃这些对象,通过这些引用的名字大概就能知道它们代表的意思。

(1)强引用

在程序代码中普遍存在,只要强引用存在,那么垃圾收集器就永远不会回收被引用的对象

(2)软引用
当一个对象与GC Roots之间存在软引用时,垃圾收集器是否回收这个对象就去决与内存的紧张程度了,如果内存空间足够,不会被回收,如果内存空间不足时,将会难逃被回收的厄运。对象与GC Roots之间存在软引用时,这个对象被称为软可达对象。在垃圾收集器还没有回收它的时候,软引用对象就像强引用对象一样,都能被程序正常使用和访问,但需要通过软引用对象间接访问(通过SoftenReference类来实现)。用来描述有用但非必须的对象,只有在内存不足时JVM才会回收该对象,这一特性可以用来解决OOM问题(内存溢出),之一特性还可以用来实现图片缓存,网页缓存。
(3)弱引用
这种引用指向的对象,一旦被垃圾收集器扫描到,就会被回收。通过WeakReference类来实现弱引用如果一个对象仅仅是偶尔使用,并且在使用时随时就能获取,但不影响此对象的垃圾收集,那么应该用WeakReference来引用该对象。
(4)虚引用
虚引用是用PhantomReference创建的引用,它是最弱的一种引用关系,一个对象是否有虚引用的存在,完全不会对其生命周期构成影响,也无法通过虚引用来获得一个实例对象。虚引用的唯一作用: 一个对象设置虚引用就是在这个对象在被垃圾收集器回收时收到一个系统通知。可以利用虚引用来做一些对象销毁前的操作,如资源释放等。

3.对象的自我拯救(生存还是死亡)

(1)概述

前面我们学了可达性算法,那一个对象在可达性算法中已经是不可达对象,那么这个对象就真正非死不可吗?其实要宣告一个对象的死亡,没有这么简单,至少要经过两次标记过程,不可达的对象只是出于“缓刑”阶段。

(2)自我拯救

如果一个对象在通过可达性算法分析后,发现没有与GC Roots相连接的引用链,那么它将会被第一次标记并进行第一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。

当对象没有重写finalize()方法或者finalze()方法已经被虚拟机调用过,虚拟机讲这两种情况都认为此对象没有必要执行finalize()方法,即自救失败。当对象重写了finalize()方法时,那么这个对象将会被放置在一个叫做F-Queue的队列之中,后面垃圾收集器将会对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己,只要与引用链上的任何一个对象建立关联即可),如把当前对象的引用this赋值给某对象的类变量/成员变量即可。第二次标记时这个对象讲将会被移除“缓刑”阶段(自救成功),如果没有与引用链上的对象建立关联,那就自救失败。

如果觉得《深入理解Java虚拟机(三)——对象已死吗》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。