JAVA虚拟机(四) ---- 对象存活判断

刚刚休完清明的小长假,星期一继续把深入理解java虚拟机的对象部分再看了几遍,不出意料,星期二和往常一样没有任何事情要做(项目经理和组长还在搞设计…),那么… , 继续来完成我的java虚拟机部分。上一节讲的是对象的创建 https://blog.csdn.net/qq_37323658/article/details/88997244

开始了…
 创建一个对象是存放于堆内存中,类的信息等是存放于方法区的,程序的运行每时每刻都有对象的创建,类的加载,而我们的堆内存和方法区空间又是有限的,那么,会不会出现堆空间和方法区放不下的情况?,毫无疑问是有可能的! 但是,在一般情况下,我们似乎从来没有为堆内存和方法区放不下担心过,原因是什么? java的垃圾回收机制!

GC:
GC出现的时间比java语言还要早,那时人们就在考虑GC的三件事情
  1. 那些内存需要回收?
  2. 什么时候回收?
  3. 如何回收?

java内存运行时内存区域,其中虚拟机栈、程序计数器、本地方法栈随线性而生,随线程而灭。这几个区域的内存分配和回收基本上都可以确定,那么这几个区域也就不用过多的考虑内存回收的问题,线程死亡的时候内存就回收了,除了上述几个区域,堆内存和方法区才是GC工作的重点。

对象的存活:
  GC回收堆内存空间的时候,堆内存存放的绝大部分是程序运行时创建的对象,而要回收这些对象首先就要判断对象是否存活? 即对象是否被引用。

引用计数法:
  在对象中添加一个引用计数器,每当这个对象被引用,那么引用计数器就 +1,当引用失效的时候就 -1,当引用计数器等于0的时候,对象就判断为死亡。(主流的java虚拟机并没采用这种方式,因为它很难解决对象之前相互循环引用的情况)

可达性分析算法:
  通过一系列的“GC Roots”对象作为起始点,从起始点往下搜索,搜索的路径被称为引用链 当一个对象没有与 GC Roots 有任何引用链想连(对象到 GC Roots 不可达),则这个对象不可用。

在这里插入图片描述
本地变量表中引用的对象可作为一个 GC Roots 指向 object a ,object a 指向 object cobject d 说明对象可达,而 object 1虽然指向了 object 2 但是他们并没有和GC Roots 相连 说明对象到 GC Roots 不可达,将被判定为可回收的对象

可作为GC Roots 的对象有下面几种:
   1. 虚拟机栈栈帧中的局部变量表引用的对象
   2. 方法区中类静态常量引用的对象
   3. 方法区中常量引用的对象
   4. 本地方法栈中JNI(一般指 native 方法)引用的对象

判定为可回收的对象也不会马上被回收,它们只是出于“缓刑”期,对象真正被回收还需要两次被标记的过程,下面是流程图。
在这里插入图片描述
对象被判定回收的流程:
   1. 对象经可达性分析后没有与RG Roots相连的引用链,将被第一次标记放入一个“即将回收”的集合里面并进行一次筛选,判断对象是否覆盖了finalize()方法,或者finalize()方法已经被执行过了,这两种情况视为“没有必要执行”
   2. 如果对象覆盖了finalize()方法,对象会被放入一个F-Queue的队列中,稍后由虚拟机创建一个finalizer线程去触发执行,finalize()方法是对象避免被回收的最后一次机会,只需要在执行finalize()方法的时候,对象重新与引用链上任何一个对象关联即可(将自己 this 赋值给某个类变量或者对象的成员变量),如果对象成功关联上了,那么第二次标记就会将这个对象移除“即将回收”的集合,如果没有关联上,对象就真正的要被回收了

finalize()方法只会被虚拟机执行一次,如果对象再一次面临被回收,finalize()方法也不会再执行了。

猜你喜欢

转载自blog.csdn.net/qq_37323658/article/details/89138443
今日推荐