1、对象被判定为垃圾的算法
对象被判定为垃圾的标准:没有被其他对象引用
1.1、引用计数算法
判断对象引用数量:
- 通过判断对象的引用数量决定对象是否可以被回收;
- 每个对象实例都设置一个引用计数器,被引用+1,完成引用则-1;
- 任何引用计数为0的对象实例都视为可被当垃圾回收
优点: 执行效率高,程序执行受引用较小;
缺点: 无法检测循环引用的情况,导致内存泄露。(两个对象相互引用构成循环引用,引用计数永远不为零)
1.2、可达性分析算法
通过判断对象的引用链是否可达来决定对象是否可以被回收。
存活的对象为蓝色。
可以作为GC root的对象:
- 虚拟机栈中引用的对象(栈帧中的本地变量表)【new了一个Object,并赋值给一个局部变量,在局部变量未销毁之前,Object可作为GC root】
- 方法区中的常量引用的对象【类里面定义一个常量保存某个对象地址,那这个对象可作为GC root】
- 方法区中的类静态属性引用的对象【基本同上】
- 本地方法栈中JNI(Native方法)的引用对象
- 活跃线程的引用对象【活跃线程引用的对象】
2、垃圾回收算法
2.1、标记-清除算法(Mark and Sweep)
标记:从根集合进行扫描,对存活对象进行标记
清除:对堆内存从头到尾进行线性遍历,回收不可达对象
缺点: 容易碎片化(因为标记-清除算法不移动存活对象)
2.2、复制算法
复制算法过程
- 分为对象面和空闲面
- 对象在对象面上创建
- 存活的对象被从对象面复制到空闲面上
- 将对象面的所有对象清除
优点:
- 解决碎片化问题
- 顺序分配内存,简单高效
- 适用于对象存活率低的场景
缺点:
对象存活率高的情况,效率低下,复制太多次了。,,而且极端情况,100%存活,就还需要更多的额外内存应付突发情况。
2.3、标记-整理算法
标记:从根集合进行扫描,对存活对象进行标记
整理:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。
优点:
- 避免内存的不连续行
- 不用设置两块内存互换
- 适用于存活率高的场景
缺点:
成本高
2.4、分代收集算法
- 垃圾回收算法的组合拳;
- 按照生命周期的不同划分区域以采用不同的垃圾回收算法
- 目的:提高JVM的回收效率
2.4.1、分代收集算法在不同版本jdk的内存
Young Generation:年轻代(复制算法)
Old Generation:老年代(标记-清除算法、标记-整理算法)
Permanent Generation:永久代
2.4.2、GC的分类
- Minor GC
- Full GC
Minor GC是年轻代中的垃圾回收算法,主要采用复制算法。
Full GC老年代相关。
Eden区,对象刚被创建出来的时候,分配在内存中的Eden区。如果放不下了,也可能放在Survivor或者老年区。
Survivor区(幸存者):from区、to区,,并无固定划分,有可能相互转换。
2.4.3、年轻代垃圾回收的过程
对象上的数字代表年龄,
触发minor GC,
年龄设置为1,
2.4.4、对象晋升老年代的情况:
- 经历一定Minor 次数依然存活的对象
- Survivor区中存放不下的对象
- 新生成的大对象(-XX:+PretenuerSizeThreshold)
2.4.5、常用调优参数:
调整最大岁数(默认15岁)到老年区,,,,,,不够用也会到老年区
2.4.6、老年代垃圾回收算法
对于采用CMS 进行老年代GC的程序而言,注意GC日志中出现
- promotion failed:进行minor GC时,survivor区放满,需要放入老年代,而老年代也放不下。
- concurrent mode failure:执行CMS GC过程中,同时有对象要放入老年代中,而老年代空间不足。