JVM排查笔记
jps
显示指定系统内所有HotSpot虚拟机进程
jps -l : 显示正在运行的虚拟机以及对应的pid
image.png
jps -v :虚拟机启动时JVM参数
image.png
jstat
虚拟机统计信息监视工具,用于监视虚拟机各种运行状态信息的命名行工具。可以显示虚拟机进程中的类装载,内存,垃圾收集,JIT编译等运行参数。格式为:jstat --option --pid --interval --count
-option: 查询的信息,可以查类装载,垃圾收集,运行编译状态三种
image.png
-pid : 进程ID
-interval : 每间隔多少毫秒查询
-count: 查询次数
jstat -gc 11056 1000 10 : 查询进程11056每隔1秒的堆情况共查询10次
image.png
实例1.接下来用命令jstat -gcutil -11056 1000 10 来学习gc堆情况,-gcutil跟-gc基本一样,可查上表说明
image.png
E : Eden区用了78.55%空间
S0,S1: Survivor0区用了65.38空间,Survivor1没有使用空间
O : 老年代使用了10.21%空间
P : 永久代(方法区)使用情况,为什么是?还不知道
YGC : 程序运行以来一共发生了MinorGC共10次,总耗时是GCT,0.303秒
FGC : 表示FullGC共2次,总耗时FGCT,0.206秒
实例2.
image.png
image.png
实例3.jstat -class 11056 1000 10 查询ClassLoader类加载相关信息
image.png
Loaded:装载的类数量
Bytes:装载的类的总大小
Unloaded:表示卸载类的数量
Bytes(第二个):表示卸载类的总大小
Time:装载类和卸载类的总时间
实例4.jstat -gccapacity 11056 查看堆各个区域使用到的最大最小空间
image.png
NGCMN : 新生代最小值(KB)
NGCMX : 新生代最大值(KB)
NGC : 当前新生代大小(KB)
OGCMN : 老年代最小值(KB)
OGCMX : 老年代最大值(KB)
PGCMN : 永久代最小值(KB)
PGCMX : 永久代最大值(KB)
Jinfo
查看和修改java配置信息工具
image.png
查看年轻代大小
image.png
jmap
用来生成堆转储快照(一般是headdump或dump文件),这个命令也可以查询finalize队列,Java堆和永久代的详细信息
格式: jmp --option --pid
image.png
实例1.jmap -histo 11056 >d:\histo.txt 生成堆中对象信息(类,实例数量,合计容量)等信息
image.png
image.png
实例2. jmap -dump:format=b,file=d:\11056.dump 11056
生成11056的dump信息,这个就可以拿给可视化工具去分析
image.png
jhat
搭配jmap使用,用来分析堆转储快照。一般不使用它来分析
jstack
可用来导出java应用程序的线程堆栈
image.png
实例.通过jstack来看是否发生死锁jstack -l 6772 >d:6772.txt
image.png image.png
通过查看导出的信息发现程序出现了死锁
public class Test {
private static Object locka = new Object();
private static Object lockb = new Object();
public static void main(String agrs[]) {
Test test = new Test();
test.deadLock();
}
private void deadLock() {
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (locka){
try{
System.out.println(Thread.currentThread().getName()+" get locka ing!");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName()+" after sleep 500ms!");
}catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" need lockb!Just waiting!");
synchronized (lockb){
System.out.println(Thread.currentThread().getName()+" get lockb ing!");
}
}
}
},"thread1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (lockb){
try{
System.out.println(Thread.currentThread().getName()+" get lockb ing!");
Thread.sleep(500);
System.out.println(Thread.currentThread().getName()+" after sleep 500ms!");
}catch(Exception e){
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" need locka! Just waiting!");
synchronized (locka){
System.out.println(Thread.currentThread().getName()+" get locka ing!");
}
}
}
},"thread2");
thread1.start();
thread2.start();
}
}
线上配置
C_LOG_TIMESTAMP=`date '+%Y-%m-%d_%H-%M-%S'`
JAVA_OPTS="$JAVA_OPTS -Djava.awt.headless=true -server -Xms50G -Xmx50G -XX:NewSize=30G -XX:MaxNewSize=30G -XX:PermSize=512m -XX:MaxPermSize=512m -Xss256k -XX:SurvivorRatio=2 -XX:NewRatio=1 -XX:+DisableExplicitGC -XX:+UseCompressedOops -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=60 -XX:MaxDirectMemorySize=10G -XX:+CMSClassUnloadingEnabled -XX:ConcGCThreads=24 -XX:+CMSScavengeBeforeRemark -XX:+CMSParallelRemarkEnabled -XX:CMSMaxAbortablePrecleanTime=20000 -XX:+PrintTenuringDistribution"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -verbose:gc -Xloggc:$CATALINA_HOME/logs/gc_$GC_LOG_TIMESTAMP.log"
export JAVA_OPTS