#JVM 故障调查教程
##java 程序 cpu100%原因排查
模拟cpu占用100%代码
public class App {
public static void main(String[] args) throws InterruptedException {
int num = 20;
Thread[] threads = new Thread[num];
for (int i = 0; i < num; i++) {
threads[i] = new Thread(new PressureRunner());
threads[i].start();
}
}
public static class PressureRunner implements Runnable {
@Override
public void run() {
while (true) {
}
}
}
}
编译:javac App.java
执行:java App.java
第一步:确认cpu占用情况及进程ID
top
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RzrvIHOd-1623727209982)(C:\Users\27381\Pictures\Camera Roll\1623122537062.png)]
第二步: 显示进程下的线程占用CPU情况
top -H -p pid
找到占用CPU最高的线程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LUJ0MiqS-1623727209984)(C:\Users\27381\AppData\Local\Temp\1623123012135.png)]
echo “obase=16;9758” | bc
线程id结果是
261E
###第三步: 导出java进程的线程栈
jstack pid > pid.tdump
执行
jstack 9745 > 9745.tdump
#查看tdump
cat 9745.tdump
代码定位
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cEmuQ6cE-1623727209985)(C:\Users\27381\Documents\1623123988844.png)]
###小结
本例子是针对业务程序引用的CPU100%的分析方法,还可能会有,并发io读写或网络读取而引起的内存资源用完引起的CPU占用100%的情况。也适用此方法来定位问题代码。一般这种情况如果计算任务释放或io读写或网络资源释放,cpu占用情况自动会下降,不会导致jvm奔溃。
还有另外一种引起的CPU占用100%情况,就是JVM空间不够引起的GC频繁回收。GC是使用多线程回收的。导致大量线程疯狂回收最终CPU资源占满。而且是不会释放的,CPU一直100%。解决办法就要调整jvm的增加内存配置。请看下节。
jvm 内存空间不足引起的CPU100% 原因排除
代码
package com.hdk.demofullgc;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* VM参数: -XX:+PrintGC -Xms50M -Xmx50M
* GC调优---生产服务器推荐开启(默认是关闭的)
* -XX:+HeapDumpOnOutOfMemoryError
*/
public class FullGCProblem {
//线程池
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
public static void main(String[] args) throws Exception {
//50个线程
executor.setMaximumPoolSize(50);
while (true){
calc();
Thread.sleep(100);
}
}
/**
* 多线程执行任务计算
*/
private static void calc(){
List<UserInfo> taskList = getAllCardInfo();
taskList.forEach(userInfo -> {
executor.scheduleWithFixedDelay(() -> {
userInfo.user();
}, 2, 3, TimeUnit.SECONDS);
});
}
/**
* 模拟从数据库读取数据,返回
* @return
*/
private static List<UserInfo> getAllCardInfo(){
List<UserInfo> taskList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
UserInfo userInfo = new UserInfo();
taskList.add(userInfo);
}
return taskList;
}
private static class UserInfo {
String name = "hdk";
int age = 18;
BigDecimal money = new BigDecimal(999999.99);
public void user() {
//
}
}
}
###运行代码:
java -cp demofullgc.jar -XX:+PrintGC -Xms50M -Xmx50M com.hdk.demofullgc.FullGCProblem
结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XN37JJ7G-1623727209987)(C:\Users\27381\Documents\1623231867792.png)]
GC 日志详解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4ang5IQI-1623727209988)(C:\Users\27381\Documents\1623295085337.png)]
GC 常用参数
-Xmn -Xms -Xmx –Xss 年轻代 最小堆 最大堆 栈空间
-XX:+UseTLAB 使用 TLAB,默认打开
-XX:+PrintTLAB 打印 TLAB 的使用情况
-XX:TLABSize 设置 TLAB 大小
-XX:+DisableExplicitGC 启用用于禁用对的调用处理的选项 System.gc()
-XX:+PrintGC 查看 GC 基本信息
-XX:+PrintGCDetails 查看 GC 详细信息
-XX:+PrintHeapAtGC 每次一次 GC 后,都打印堆信息
-XX:+PrintGCTimeStamps启用在每个 GC 上打印时间戳的功能
-XX:+PrintGCApplicationConcurrentTime