Jstack找到线程的快照
jvm提供其他命令作用
jps: 虚拟机进程状况工具,类似linux的ps命令
jstat:虚拟机统计信息监视工具,经常看gc情况的会使用到
jinfo: java配置信息工具
jmap: java内存映射工具,dump,查看堆情况一般会用到
jhat: 虚拟机堆转储快照分析工具,分析dump文件
jstack: Java堆栈跟踪工具,查看线程的堆栈情况
整个jstack文件分析
一般我们比较关注WAITING 、 TIMED_WAITING和BLOCKED状态的线程,可以利用以下命令进行分类
如果 WAITING 之类的特别多,那么多半是有问题啦。
GC
可以在程序启动的时候,开启GC日志,一些参数说明参考https://lihuimintu.github.io/2019/02/19/gcLog/
jstat -gc pid 1000命令来对 gc 分代变化情况进行观察,1000 表示采样间隔(ms),S0C/S1C、S0U/S1U、EC/EU、OC/OU、MC/MU 分别代表两个 Survivor 区、Eden 区、老年代、元数据区的容量和使用量。YGC/YGT、FGC/FGCT、GCT 则代表 YoungGc、FullGc 的耗时和次数以及总耗时。
S0C 年轻代中第一个survivor(幸存区)的容量 (字节)
S1C 年轻代中第二个survivor(幸存区)的容量 (字节)
S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (字节)
S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (字节)
EC 年轻代中Eden(伊甸园)的容量 (字节)
EU 年轻代中Eden(伊甸园)目前已使用空间 (字节)
OC Old代的容量 (字节)
OU Old代目前已使用空间 (字节)
PC Perm(持久代)的容量 (字节)
PU Perm(持久代)目前已使用空间 (字节)
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT从应用程序启动到采样时gc用的总时间(s)
新生代一般是占用堆的1/3的空间,新生代又分为Eden区、ServivorFrom、ServivorTo三个区。Eden区内存不够,会触发垃圾回收,一般这个区域垃圾回收的采用复制算法,老年代一般是标记清除算法。在Java8以后的时代,永久代被移除了,而是利用元数据区所取代,元空间和永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用内存,因此元空间的大小只是受到本地内存的限制,类的元数据放入native memory,字符串池和类的静态变量放入java队中,这样元数据空间不再由MaxPermSize控制,而是由系统的实际可用空间来控制。
新生代一般使用minjorGC(复制算法)
MinjorGC(YONGGC)过程:
对象直接在年轻代中的Eden区进行分配,如果Eden区域没有足够的空间,那么就会触发YGC(Minor GC),YGC处理的区域只有新生代。因为大部分对象在短时间内都是可收回掉的,因此YGC后只有极少数的对象能存活下来,而被移动到S0区(采用的是复制算法)
1.eden、ServivorFrom中存活对象复制到ServiorTo,年龄+1
2.清空eden、ServivorFrom中的对象
3.ServivorTo和servicevicorFrom互换,原来 to成为下次GC时的from。
进入老年代的4个条件:
YGC时,To Survivor区不足以存放存活的对象,对象会直接进入到老年代
经过多次YGC后,如果存活对象的年龄达到了设定阈值,则会晋升到老年代中。YGC时,To Survivor区不足以存放存活的对象,对象会直接进入到老年代。
动态年龄判定规则,To Survivor区中相同年龄的对象,如果其大小之和占到了 To Survivor区一半以上的空间,那么大于此年龄的对象会直接进入老年代,而不需要达到默认的分代年龄。
大对象:由-XX:PretenureSizeThreshold启动参数控制,若对象大小大于此值,就会绕过新生代, 直接在老年代中分配。
老年代空间算法回收:
老年代的对象还是比较稳定,所以fullGC不会频繁执行,在进行fullgc前一般都进行一次yonggc,使得有新生代进入老年代,导致空间不够用才触发,当无法找到足够大的连续分配给新创建对象时也会提前触发一次fullgc进行垃圾回收腾出空间。fullgc采用标记清除算法或者标记复制算法。
fullGc什么时候发生
老年代的内存使用率达到了一定阈值(可通过参数调整),直接触发FGC。
空间分配担保:在YGC之前,会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间。如果小于,说明YGC是不安全的,则会查看参数 HandlePromotionFailure 是否被设置成了允许担保失败,如果不允许则直接触发Full GC;如果允许,那么会进一步检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果小于也会触发 Full GC。
Metaspace(元空间)在空间不足时会进行扩容,当扩容到了-XX:MetaspaceSize 参数的指定值时,也会触发FGC。
System.gc() 或者Runtime.gc() 被显式调用时,触发FGC。
垃圾收集器
2.5.1 分代收集器
ParNew:一款多线程的收集器,采用复制算法,主要工作在 Young 区,可以通过-XX:ParallelGCThreads参数来控制收集的线程数,整个过程都是 STW 的,常与 CMS 组合使用。
CMS:以获取最短回收停顿时间为目标,采用“标记-清除”算法,分 4 大步进行垃圾收集,其中初始标记和重新标记会 STW ,多数应用于互联网站或者 B/S 系统的服务器端上,JDK9 被标记弃用,JDK14 被删除,详情可见JEP 363。
2.5.2 分区收集器
G1:一种服务器端的垃圾收集器,应用在多处理器和大容量内存环境中,在实现高吞吐量的同时,尽可能地满足垃圾收集暂停时间的要求。
ZGC:JDK11 中推出的一款低延迟垃圾回收器,适用于大内存低延迟服务的内存管理和回收,SPECjbb 2015 基准测试,在 128G 的大堆下,最大停顿时间才 1.68 ms,停顿时间远胜于 G1 和 CMS。
Shenandoah:由 Red Hat 的一个团队负责开发,与 G1 类似,基于 Region 设计的垃圾收集器,但不需要 Remember Set 或者 Card Table 来记录跨 Region 引用,停顿时间和堆的大小没有任何关系。停顿时间与 ZGC 接近,下图为与 CMS 和 G1 等收集器的 benchmark。
上下文切换
针对频繁上下文问题,我们可以使用vmstat命令来进行查看
vmstat pid # cs(context switch)一列则代表了上下文切换的次数。
# 特定的 pid 进行监控那么可以使用 pidstat -w pid命令,cswch 和 nvcswch 表示自愿及非自愿切换。
pidstat -w pid