文章目录
- 前言
- 一、前置准备
- 二、jvm 常用命令
- 1.jps
- 2.jmap
- 3、Jstack
- 3.1、该命令能得到运行java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。下面我们用一个示例来学习一下
- 相互争夺资源导致死锁。
- 3.2 jstack命令也常用来找出占用cpu最高的线程堆栈信息
- 1、执行后代码后,top 查看当前cpu 使用状况,cpu 占用在98%左右
- 2,按H(大写),获取每个线程的内存情况
- 3,找到内存和cpu占用最高的线程tid,比如19664
- 4,转为十六进制得到 0x2703,此为线程id的十六进制表示
- 5,执行 jstack 72414|grep -A 10 0x2703,得到线程堆栈信息中 0x2703 这个线程所在行的后面10行,从堆栈中可以发现导致cpu飙高的调用方法
- 总结:
前言
1、如何分析jvm cpu占用率过高的方法。
2、如何排查线上jvm内存泄漏问题。
3、如何定位jvm 线程死锁问题定位。
4、如何解决jvm 频繁full gc 问题等。
这些问题会通过这篇文章一步一步的去解决它。
一、前置准备
1、先准备一个web 服务: eureka-server.jar 并启动
java -jar eureka-server.jar
下载链接: https://pan.baidu.com/s/1Y5DG2H_GGGXlSyDUVFut1A 提取码: lsuw
二、jvm 常用命令
1.jps
查看刚启动erureka服务进程id为:4123
[root@centos-linux ~]# jps
4280 Jps
4123 jar
2.jmap
2.1 此命令可以用来查看内存信息,实例个数以及占用内存大小,将其写入obj_info.txt 文件中:
[root@centos-linux opt]# jmap -histo 4123 > obj_info.txt
- num:序号
- instances:实例数量
- bytes:占用空间大小
- class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]
2.2 查看堆的信息。
[root@centos-linux opt]# jmap -heap 4123
Attaching to process ID 4123, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.181-b13
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 260046848 (248.0MB)
NewSize = 5570560 (5.3125MB)
MaxNewSize = 86638592 (82.625MB)
OldSize = 11206656 (10.6875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 20643840 (19.6875MB)
used = 4067112 (3.8787002563476562MB)
free = 16576728 (15.808799743652344MB)
19.701334635416668% used
Eden Space:
capacity = 18415616 (17.5625MB)
used = 3581160 (3.4152603149414062MB)
free = 14834456 (14.147239685058594MB)
19.446322077958186% used
From Space:
capacity = 2228224 (2.125MB)
used = 485952 (0.46343994140625MB)
free = 1742272 (1.66156005859375MB)
21.80893841911765% used
To Space:
capacity = 2228224 (2.125MB)
used = 0 (0.0MB)
free = 2228224 (2.125MB)
0.0% used
tenured generation:
capacity = 45654016 (43.5390625MB)
used = 36456800 (34.767913818359375MB)
free = 9197216 (8.771148681640625MB)
79.85453021263234% used
23817 interned Strings occupying 3034368 bytes.
2.3 堆内存dump(重点,常用来分析OOM问题)。
[root@centos-linux opt]# jmap -dump:format=b,file=eureka 4123
[root@centos-linux opt]# jmap -dump:format=b,file=eureka.hprof 4123
Dumping heap to /opt/eureka.hprof ...
Heap dump file created
线上配置一般会设置内存溢出自动导出dump文件(内存很大的时候,可能会导不出来)
1. -XX:+HeapDumpOnOutOfMemoryError
2. -XX:HeapDumpPath=./ (路径)
好下面我们模拟一下内存溢出的一个场景来分析一下,实例代码如下。
public class OOMTest {
public static List<Object> list = new ArrayList<>();
// JVM设置
// -Xms5M -Xmx5M -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./jvm.dump
public static void main(String[] args) {
List<Object> list = new ArrayList<>();
int i = 0;
int j = 0;
while (true) {
//往list 中不停放入student 对象直到OOM
list.add(new Student(i++, UUID.randomUUID().toString()));
new Student(j--, UUID.randomUUID().toString());
}
}
}
将jvm.dump文件,导入jvisualvm命令工具来分析(jdk bin 目录下有该工具,执行运行即可)
可以明显看出堆栈中有大量的student 对象,有小伙伴会有疑问,那排第一的char[]、String 是什么呢?
3、Jstack
3.1、该命令能得到运行java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。下面我们用一个示例来学习一下
public class LockTest {
private static Object lock1 = new Object();
private static Object lock2 = new Object();
public static void main(String[] args) {
new Thread(() -> {
synchronized (lock1) {
try {
System.out.println("thread1 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
//已获取到lock1 尝试获取lock2
synchronized (lock2) {
System.out.println("thread1 end");
}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
try {
System.out.println("thread2 begin");
Thread.sleep(5000);
} catch (InterruptedException e) {
}
//已获取到lock2 尝试获取lock1
synchronized (lock1) {
System.out.println("thread2 end");
}
}
}).start();
System.out.println("main thread end");
}
}
相互争夺资源导致死锁。
##用jstack加进程id查找死锁
jstack 64992
当然我们也可以用JVisualVM 工具来分析。
3.2 jstack命令也常用来找出占用cpu最高的线程堆栈信息
/**
* 运行此代码,cpu会飙高
*/
public class CPUTest {
public int calculate() {
int a = 1;
int b = 2;
int c = (a + b) * 10;
return c;
}
public static void main(String[] args) {
CPUTest cpuTest = new CPUTest();
while (true){
cpuTest.calculate();
}
}
}
1、执行后代码后,top 查看当前cpu 使用状况,cpu 占用在98%左右
使用命令top -p <pid> ,显示你的java进程的内存情况,pid是你的java进程号,比如72414
top -p 72414
2,按H(大写),获取每个线程的内存情况
3,找到内存和cpu占用最高的线程tid,比如19664
4,转为十六进制得到 0x2703,此为线程id的十六进制表示
5,执行 jstack 72414|grep -A 10 0x2703,得到线程堆栈信息中 0x2703 这个线程所在行的后面10行,从堆栈中可以发现导致cpu飙高的调用方法
总结:
- 学习了jvm 的常用命令:jps、jmap、jstack 等常用命令以及些经典案例的排查方法。后面我会继续更新相关jvm 的性能调优的方法,以及一些强大好用的工具使用。大大方便了我们解决线上问题,提高效率。有兴趣小伙伴点个关注,同时给个赞。你们的肯定是我继续分享的动力~~