JVM调优使用到的所有命令
cmd 使用 java -XX:PrintFlagsFinal -version
Serial(最古老的)
STW时间不可以接受的
其他垃圾回收器全部是对stw时间(停顿时间)进行优化的
停顿时间是第一的,吞吐量是第二的
凡是带Serial的全部都是单线程的(不过是分代的)
Serial,ParNew,ParallelScavenge 是年轻代
CMS,SerialOld,ParallelOld是老年代
新诞生的去年轻代,很顽固的去老年代
Serial(单线程年轻代),SerialOld(单线程老年代)
ParallelScavenge,ParallelOld,这两个经常一起使用,jdk1.8使用的就是这两个(PS+PO)
从CMS开始jvm进行了降低停顿时间的一系列的努力,jdk1.9就不使用了
如果系统比较卡顿使用G1不要使用CMS
CMS分为四个阶段
提前标记出需要清理的垃圾,之后再清理标记的垃圾
并发标记存在漏标的情况,在重新标记时必须是STW时间(单线程的,防止其他线程使用),再清理
在ZGC之前的CMS和G1都是使用"三色标记"进行标记
三色标记
A,B,D都被标记好后,D的标记消失了,会造成D没有被回收,在下次重新垃圾回收时可能被回收掉
使用三色标记法,标记完的为黑色,刚标记完的为灰色,即将标记的为白色,
当从B指向D时(B可以指向D时,垃圾收集器不会去扫描D),指向没有了,
此时(同时发生的)A重新扫描的了D,当知道D为白色的时候,就知道D是漏标的了
m1(垃圾回收线程),属性1(m1)已经标完了,属性2(m2)正在标记,此时A已经为灰色了
m2(业务逻辑线程),因为m1使A为灰色,所以A会指向一个白色对象,当A指向的对象为D的
同时m3(垃圾回收线程)发现A被m2正在标记,不会回收,m1再次标记,将A(属性1)标完黑色
此时黑色的A指向了一个白色的D,D漏标了
当数据量庞大时,时间依然会很长
G1会分为一块一块的内存,
G1实际还是分代的只是不在是一大片区的,而是对部分块内存的划分
https://zhuanlan.zhihu.com/p/59861022
每一块的内存都会有一个头空间(Rset,大概占块内存的1-20%)中的引用来指向该块内存的所有数据
将B指向D的指向定义为一个个引用(指针),每个指向都会创键引用,标记完就存储该指向的引用
当找到漏标的节点时,去引用中查询是否有其他引用过该节点,有的话该漏标的对象是垃圾,没有就不是垃圾了
虽然指向消失了但是引用没消失
G1依然无法避免FGC,依然很慢
G1有很多阶段都是STW的,当数据量大时,依然很慢
G1将整个堆分成一个个的Regin(根据实际JVM内存的大小/2048),那个垃圾最多先清理那块内存
ZGC 牛逼(停顿10ms以内,支持16TB)
与内存多大无关,停顿时间都是10ms以内
NUMA与UMA
对内存的使用,CPU的优先级都是一致的(UMA同一内存访问)
当CPU变多时,会有大量时间用于CPU对内存的竞争(谁拿到锁谁使用)上了
CPU绑定片区内存,CPU优先使用它绑定的内存(内存的优先级不同了)
目前不分代(可能分冷热对象)ZGC来源于Asul C4
ZGC只支持64位操作系统
Regain部分压缩
将块内存中有用的部分复制并压缩到新的空的块内存中,再将旧的块内存擦除即可(GC的操作根本)
颜色指针 标记法(在指针上动手脚)
原来的GC的指向信息记录在块内存的头部
ZGC的指向信息记录在指针中
当一个指针指向一个对象时,指向对象的信息是记录在指针上的,
不是像G1记录在对象的头空间内(当头空间内还有残留信息时该
块内存就无法被立即使用,必须全部清除才可使用,与对象无关)
当对象可以使用时,就会立即被使用,不用等待
指针是可以存储信息的
将指针用于存储信息的空间(低42位指向对象,2的42次方=4TB)
后面4位用来存储对象不同状态m0,m1,remapped,finalizable
后面18位没有用
JDK13(2的44次方=16TB),目前最大16T
CPU通过总线连接到内存
总线分为数据总线,地址总线,控制总线(传指令)
目前的主板的地址总线最宽48bit,48-4(颜色)-44(存储)=0,只能16T
颜色指针的操作
在ZGC出现以前当GC收集掉,指针所指向的内存时,会从被擦掉的内存中收集的
有用的复制到新的内存中,原指针所存的引用会擦掉,重新写入
新的引用,这个过程是用写屏障来实现整个对象的移动
ZGCu使用的是读屏障(4%的系统消耗)
当对从擦除的内存中复制到新内存的信息时,会先读一下被修改的指针(原指针),
读取到是被修改的指针时,读取指针上的存储的复制信息的地址,进行一次指针的
跳跃(读屏障),指针跳跃到复制信息所在的新的内存地址
ZGC追求响应时间不追求吞吐量