注:如果你的程序运行很久,积累大量的dump信息,这个时候你使用jmap很有可能会直接把你的程序卡死,所以jmap这个命令不适合线上使用,在进行测试和压测的时候使用比较好。在线上环境,慎用jmap。
内存飙高:
1.在官网下载MemoryAnalyzer:https://www.eclipse.org/mat/
2.创建一个java测试程序mat-test,写如下代码:
public class CarModel {
public boolean run()
{
try {
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName()+" "+new Date().toString());
return true;
}
catch(Exception ex)
{
return false;
}
}
}
public class App {
public static void main(String[] args) {
System.out.println("start:");
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 5000; i++) {
try {
Thread.sleep(1000);
executor.execute(new Runnable() {
@Override
public void run() {
new CarModel().run();
}
});
} catch (Exception ex) {
}
}
executor.shutdown();
startWhile();
System.out.println("end");
}
private static void startWhile() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) ;
}
}).start();
}
}
3.打包,部署到服务器,这里我使用的是docker部署的,如果你不知道如何用docker部署,请参考我的另外一篇博客:https://blog.csdn.net/dap769815768/article/details/86561566
4.启动容器后,使用
docker exec -it mat-test /bin/bash
进入到容器内。使用
ps -ef |grep java
查看这个容器里面你的java程序运行的pid。使用jmap命令:
jmap -dump:file=test.dump 1
到处dump文件,这里的1是我的程序的pid。
5.成功后,按ctr+d,退出容器,使用命令:
docker cp mat-test:test.dump ./test.dump
将容器内生成的dump文件导出Linux环境,然后下载到本地。
6.打开MemoryAnalyzer,file=》open heap dump,选择Leak Suspects Report,打开之后默认显示界面如下:
7.选择Overview=》Unreachable Objects Histogram,可以查看到类被实例化的数量:
8.在default_report选下卡里面,有具体的统计信息,可以看到我们这个例子中,统计信息总共分成三部分:
紧接着下面就是Problem的具体描述:
点击Details可以查看详细内容。这里不再深入探讨。
CPU飙高:
我们的这个例子有一个死循环,这会导致cpu飚高,如果是内存飚高,刚才的方式是可以清晰地看到具体哪些东西占用了内存。但是看不到cpu被占用的情况,要看cpu占用的情况,需要使用jstack这个工具。
1.首先进到我们的Linux服务器,使用top命令查看cpu使用情况
这里的java程序cpu占用率始终在99%以上,我们知道,之所以这么高,是因为我们故意写了一个死循环导致的。
2.使用docker exec -it mat-test /bin/bash进入到容器里面,使用jstack命令看看在容器内部占用cpu高的是哪个进程,找到进程pid。
在容器内部,这个进程的id是1。
3.使用top -Hp 1,可以查询到具体是哪个线程占用cpu高:
可以看到是pid为15的线程cpu占用偏高。
4.使用jstack 1,查看具体信息:
如果你还记得刚才的那个线程id,你就会发现,这里标注的16进制数字转过来正好是15,没错,也就是在代码的第14行的一个run方法里面,有大量的cpu占用。这个run方法里面的内容,就是我们写的死循环。
好了,到这里,cpu飚高的问题就定位到具体的代码位置了,下面就是找到具体的代码,分析出现飚高的原因了,这个例子里,代码很好分析,就是因为死循环,而实际上大部分场景下,可能都没那么好分析,比如有些网络请求阻塞了而又没有去设置网络请求等待超时时间,这样等待时间就会无限长,积攒久了,也可能会导致cpu飚高。