jvm垃圾收集器详解
1. 简介
垃圾收集器虽然从Serial -> Parallel->ParNew->CMS->G1->ZGC一步步演化,但是新的垃圾收集器不一定就适合所有场景,从垃圾收集的发展进程的可以看出,垃圾收集器的演化无非因为一下几点:
- 贴合当下的硬件,能够更友好的使用硬件资源
- 减少STW(Stop The World)的时间,提高用户体验
2. 基本概念
2.1 jvm内存模型
- 本地方法栈: native方法
- 栈:一个方法对应一块栈帧内存空间,主要存储局部变量表、操作数栈、动态链接、方法出口
- 程序计数器:每一个栈都有自己的程序计数器,用户恢复现场
- 堆:内存分配和垃圾回收的主要场所
- 方法区:运行时常量池,主要存储元空间、常量、静态变量、类信息
2.2 对象内存分配流程
- 对象逃逸分析:当一个对象在方法中被定义后,没有被外部方法引用
- 方法内部的对象,可以直接分配在栈的,但是太大了也只能放在堆中
- 如果对象不会逃逸可以将该对象在栈上分配内存,这样该对象所占用的内存空间就可以随栈帧出栈而销毁,就减轻了垃圾回收的压力
- 栈上分配依赖于逃逸分析和标量替换
- 标量替换:标量指不可被进一步分解的量,而JAVA的基本数据类型就是标量
- 确认对象不逃逸,将对象的成员变量拆分成若干个被这个方法使用的成员变量替换
2.2 垃圾查找算法
- 引用计数法: 效率高,无法解决循环引用的问题(基本不用)
- 可达性分析法:将“GC Roots” 对象作为起点,从这些节点开始向下搜索引用的对象,找到的对象都标记为非垃圾对象,其余未标记的 对象都是垃圾对象
- 根节点(root)
- 线程栈的本地变量
- 静态变量
- 本地方法栈的变量
2.3 垃圾收集算法
- 分代收集理论
- 根据存活周期不同将内存分为几块
- 新生代每次收集都会有大量的对象死亡(一般采用复制算法)
- 老年代的对象存活的几率比较大(一般采用标记整理或者标记清除)
- 复制算法:将内存分为大小相同的两块,每次使用一块,当一块内存使用完后,就将还存活的对象复制到另一块,清理掉当前的块内存
- 优点:不会产生内存碎片,效率高
- 缺点:内存被分割为两份,占用内存较多
- 标记清除算法:标记存活的对象,清除没有被标记的对象(会造成大量的内存碎片,最后肯定会进行一次整理算法)
- 优点:内存占用低
- 缺点:效率不高,容易使内存碎片化
- 标记整理算法:标记存活的对象,让所有存活的对象向一端移动,然后直接清理掉端边界以外的内存
- 优点:内存占用低
- 缺点:效率不高,比清除算法还要低,清除算法会将多次碎片内存进行一次整理
3. 垃圾收集器
- 黑色相连: 表示可以相互配合使用
- 红色相连:表示在最后可能会转变成另外一种方式回收