Java中JVM判断对象已死的基本算法分析

jvm中有各种的垃圾收集器,每个收集器都有各自的算法。但是一切的根本都需要找到找到应该被消除的对象,理解如何找到死亡对象才是理解垃圾收集器的基础。

一、两个基本算法

1、 引用记数法:对象中加一个引用计数器,每次被引用计数器加一,引用失效减一,当减到0的时候就不会在被再引用了,就可以回收了。

优点:原理简单,效率高。

缺点:有很多例外情况要用大量额外的处理,比如两个对象相互引用

2、 可达性分析:通过一系列“GC Roots”的根对象为起始,根据引用关系向下搜索,搜索路径形成引用链,而那些没有在任何引用链上的叫做不可达对象,都是不可能被再次使用的。如下图,红色部分就是需要回收的。

1GCRoots可达性图解.png

两种算法对比如下:
2两种算法对比.png

二、GC Roots包含哪些

可达性分析首先要确认的是GC Roots,只有选择合适的GC Roots才能真正的找到应该存在的对象和排除不应该存在的对象。GC Roots主要包含以下:

a、虚拟机栈中的对象,就是各个线程的方法里面的方法参数、局部变量、临时变量。

b、方法区中类的静态属性引用的对象。

c、方法区中常量引用的对象,比如字符串常量池的引用。

d、本地方法栈引用的对。

e、虚拟机内部的引用,基本类型对应的class对象,常驻异常对象,系统类加载器。

f、所有被同步锁(synchronized)持有的对象。

g、Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存。

可以把上面的大概分成几个方面,如下图:

3GC Roots分类.png

GC Roots实际上就是当前JVM必须要的对象,可以分成三类。

第一类是JVM线程里面直接引用的对象,相当于正在执行的方法里面的对象,这些肯定是必须存活的。

第二类是设置的一些静态常量,比如我们在类里面用static final修饰的一些对象,这类对象至jvm启动到结束都会一直存在。

第三类就是JVM本身所需要的对象,这类对象肯定不能被回收。

三、Java的引用

可达性分析就是根据引用来判断的,那么Java中有哪些引用呢?一共分4类引用:

1、强引用:常见的引用赋值,垃圾收集器不回收。ObjectA a=new ObjectA();

2、软引用:还有用,但非必须。在系统将要发生内存溢出前,把他们列为回收范围进行二次回收,JDK1.2后SoftReference类实现。

3、弱引用:非必须,比软引用更弱。下次垃圾收集器无论内存是否足够,均回收。JDK1.2后WeakReference类实现。

4、虚引用:最弱引用关系,虚引用不影响对象的生存,也无法通过虚引用来取得对象实例。唯一作用是可以在垃圾收集器回收前收到一个系统通知。JDK1.2后PhantomReference类实现。

对比如下图:
4引用对比.png

后面三个引用我们平时使用几乎没有,多在一些源码中出现,依靠3个类实现:SoftReference、WeakReference、PhantomReference。在看到这三个类的时候能知道对应的含义。

四、两次标记

当一个对象被标记为不可达对象的时候并不一定是马上被回收的。如果对象重写了finalize()方法,并且finalize()方法还没有被执行过(finalize()方法只会被执行一次),那么这个对象会被放入F-Queue队列里面。会有一个Finalizer线程去执行队列里面对象的finalize()。如果finalize()方法把这个对象重新赋值给了其他变量,就叫做逃脱成功。

垃圾收集器会对F-Queue队列里的对象进行第二次标记,如果在上一步中成功逃脱的就会移除即将回收的集合。

对于逃脱的对象,在下次被标记成不可达对象时,就会被直接回收,因为finalize()方法已经执行过一次了。​
5两次标记.png

Java程序员日常学习笔记,如理解有误欢迎各位交流讨论!
Java程序员日常学习笔记

发布了20 篇原创文章 · 获赞 48 · 访问量 1662

猜你喜欢

转载自blog.csdn.net/weixin_46421629/article/details/105232784
今日推荐