JVM垃圾回收机制
作者:互联网
垃圾回收机制
对象称为垃圾的判断依据
在堆空间和元空间中,GC这条守护线程会对这些空间开展垃圾回收工作,那么GC如何判断这些空间的对象是否是垃圾,有两种算法:
- 引用计数法
对象被引用,则计数器+1,如果计数器是0,那么对象将被判定为垃圾,于是被回收。但是这种算法没有解决循环依赖的对象,因此JVM目前主流的厂商没有采用这种算法。
- 可达性分析算法 GC Roots根
- gc roots根节点:在对象的引用中,会有那么几种对象的变量:来自线程栈中局部变量表中的变量,静态变量,本地方法栈中的变量,这些变量被称为gc roots根节点
- 判断依据:gc在扫描堆空间中某个节点时,向上遍历,看能不能遍历到gc roots根节点,如果不能,则意味这个对象是垃圾。
对象中的finalize方法
Object类中有一个finalize方法,也就是说任何对象都有一个finalize方法,这个方法是对象被回收前的最后一个救命稻草。
- GC在垃圾对象回收前,先标记对象,被标记的对象的finalize方法被调用
- 调用finalize方法如果对象被引用,那么第二次标记该对象,被标记的对象将被移除即将被回收的集合,继续存活。
- 调用finalize方法如果对象没有被引用,那么将会被回收
注意,finalize方法只会被调用一次
对象的逃逸分析
在jdk1.7之前,对象的创建都是在堆上完成的,但是会有个问题,方法中的未被外部访问的对象。
这种对象没有被外部访问,且在堆空间上频繁创建,当方法结束,需要被gc,浪费了性能。
所以在1.7之后,就会进行一次逃逸分析(默认开启),于是这样的对象就直接在栈上创建,随方法的出栈而被销毁,不需要进行GC,减轻了垃圾回收的压力。
在栈上分配内存的时候:会把聚合量替换成标量,减少栈空间的开销,也为了防止栈上没有足够连续空间来创建对象。
- 标量:java中的基本数据类型(不可再分)
- 聚合量:引用数据类型。
垃圾回收算法
标记清除算法、复制算法、标记整理算法
标记清除算法
复制算法
注:元空间中新生代的幸存者s0、s1区就是使用的复制算法
标记整理算法
标记存活对象,让所有存活对象向一端移动,再清除其后所有可回收内存。
分代收集算法
- 堆空间被分成了新生代(1/3)和老年代(2/3),新生代中被分成了eden(伊甸园区)(8/10)、survivor1(1/10)、survivor2(1/10)
- 对象的创建在eden,如果放不下则触发minor gc(轻gc)
- 对象经过一次minor gc后,存活的对象会被放到survivor区,并且年龄+1
- survivor区执行复制算法,当对象年龄达到15,进入到老年代。
- 如果老年代放满,就会触发full gc(重 gc)
在进行minor gc时,什么样的对象会进入老年代:
- 对象的年龄达到15岁
- survivor区放不下,survivor中的所有幸存对象全部进入老年代。
对象进入到老年代的条件
-
大对象直接进入到老年代(减少大对象在s区来回复制的开销):大对象可以通过参数设置大小,多大的对象被认为是大对象。
-XX:PretenureSizeThreshold
-
当对象的年龄到达15岁时进入老年代,这个年龄可以通过参数设置
-XX:MaxTenuringThreshold
-
根据对象动态年龄判断,如果s区中的对象总和超过了s区中的50%,那么下一次做复制的时候,把年龄大于等于这次最大年龄的对象都一次性全部放入老年代。
-
老年代空间分配担保机制:在minor gc时,检查老年代剩余可用空间是否大于年轻代里现有的所有对象(包含垃圾)。如果大于等于,则做minor gc。如果小于,看是否配置了担保参数的配置:
-XX: -HandlePromotionFailure
,如果配置了,那么判断老年代剩余的空间是否小于历史每次minor gc后进入老年代的对象的平均大小。如果是,则直接full gc,减少一次minor gc。如果不是,执行minor gc。如果没有担保机制,直接full gc。
标签:finalize,对象,回收,算法,gc,垃圾,JVM,minor 来源: https://blog.csdn.net/CAUC_yangxiao/article/details/121729652