垃圾收集算法:分代算法、复制算法、标记清除算法、标记整理算法
serial、serial old partNew、CMS parallel、parallel old G1 ZGC
parallel 关注的是吞吐量即高效率使用CPU 新生代复制、老年代标记整理
CMS 关注的是最短停顿时间 初始标记、并发标记、重新标记、并发清理、并发重置 标记清除
黑白灰三色标记:
黑色代表被垃圾收集器访问过,安全存活
白色代表被垃圾收集器访问过,不过存在至少一个引用没有被扫描过
灰色代表没有被垃圾收集器访问过,所以在可达性分析开始阶段,所以对象都是白色的,分析完之后仍然是白色代表不可达,后面会被回收
G1 写屏障 SATB(原始快照) CMS 写屏障 增量更新
G1 没有整块的年轻代,老年代 将堆划分为大小相同的独立 region old eden survivor humongous 初始标记 并发标记 最终标记 筛选回收(算法会根据回收内存大小和时间成本择优回收)
G1 整体是标记整理算法,局部是复制算法 还没实现并发回收 Shenandoah实现了并发回收,可以看成是G1的升级版本
G1 初始标记(STW)、并发标记、最终标记(停顿)、筛选回收(停顿) XX:MaxGCPauseMillis 设置可预测的停顿时间
如何选择收集器
小于100M用串行,4G以下用parallel,4-8G可以用partNew+CMS,8G以上用G1,几百G用ZGC
安全点与安全区域 GC不是随时触发,而是等所以线程运行到安全点才触发的:
1、方法返回之前 2、调用某个方法之后 3、抛出异常的位置 4、循环的末尾
安全点是针对正在运行的线程,安全区域针对sleep或者interrupt的线程,所以安全区域就是代码片段中,引用关系不会发生变化的地方
jmap -heap 进程id ,这个命令用于查看堆内存数据
jmap -dump dump出堆内存
top -p pid,然后按H,获取每个线程的内存情况,然后可以拿着线程id转为十六进制,去掉前面的0X,得到例如1234,然后执行 jstack 线程id|grep -A 10 1234,从堆栈中可以发现导致CPU飚高的方法
jinfo -flags 进程id 查看 jvm配置
jstat -gc pid 查看堆内存各部分使用量
jstat -gcnew pid 新生代垃圾回收统计
jstat -gcnewcapacity pid 新生代内存统计
jstat -gcold pid 老年代垃圾回收统计
jstat -gcoldcapacity pid 老年代内存统计
jstat -gcmetacapacity pid 元数据空间统计
jstat -gcutil pid
合理估算线程每秒产生对象大小,合理分配Eden、survivor、old区,尽量让young gc后存活对象小于survivor区的50%,都留存在年轻代,尽量别让对象进入老年代,减少full gc的频率