什么是调优?
每执行一个Java命令,就分配一个JVM,调优时不要混淆。
- 根据需求进行JVM规划和预调优
- 优化运行JVM的运行环境(慢、卡顿)
- 解决JVM运行过程中出现的各种问题(内存泄露、内存溢出OOM)
生产JVM的CPU爆了,怎么排查?
生产方案:
- 提前设置好启动参数 -XX:HeapDumpOnOutOfMemoryError 当OOM内存爆了,就生成堆存储文件
- 做负载均衡,把某一台机摘除流量后,再分析(或把流量复制一份到备份机,然后对备份机进行分析)
- 使用TCP copy命令把流量复制并同时打到生产环境和测试环境,在测试环境做性能分析和观察
- 在压测环境分析
- 堆存储文件分析工具:MAT/jhat/jvisualvm
相关指令:top/jps/jinfo/jstat/jstack/jmap
- 找出占CPU高的进程:top命令,查询是什么线程在占用这个CPU比较高
- 找出进程占CPU高的线程:top -Hp ${pid} 显示所有线程的CUP占比,看哪个线程占比高
- jstack 根据线程编号,用jstack查看线程的调用栈信息,对比看是哪个线程
- 若是VM线程,那就是一直在FGC,若是频繁FGC,需要看是否正常回收(回收不掉?内存泄露)
- 若是业务线程,则查看业务代码问题
- jmap -histo 每种类型的class占用的内存&对象数量
- Java VisualVM 可分析堆存储文件;也可以远程连接到业务容器,但会影响10%-15%的性能且会产生安全问题(多开了一些端口)。
java指令
-
JVM的命令行参数参考:https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
-
HotSpot参数分类
标准: - 开头,所有的HotSpot都支持
非标准:-X 开头,特定版本HotSpot支持特定命令
不稳定:-XX 开头,下个版本可能取消
java -XX:PrintFlagsFinal -version|wc -l #查看所有-XX 参数命令
1、查看当前使用的GC
命令:${JAVA_HOME}/bin/java -XX:+PrintCommandLineFlags -version
如下 -XX:+UseParallelGC ,使用的是并行收集器
2、jps:打印进程信息 jinfo
package com.vip.fcs.gc;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 从数据库中读取信用数据,套用模型,并把结果进行记录和传输
*/
public class T15_FullGC_Problem01 {
private static class CardInfo {
BigDecimal price = new BigDecimal(0.0);
String name = "张三";
int age = 5;
Date birthdate = new Date();
public void m() {}
}
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
public static void main(String[] args) throws Exception {
executor.setMaximumPoolSize(50);
for (;;){
modelFit();
Thread.sleep(100);
}
}
private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
taskList.forEach(info -> {
// do something
executor.scheduleWithFixedDelay(() -> {
//do sth with info
info.m();
}, 2, 3, TimeUnit.SECONDS);
});
}
private static List<CardInfo> getAllCardInfo(){
List<CardInfo> taskList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
CardInfo ci = new CardInfo();
taskList.add(ci);
}
return taskList;
}
}
jps:查看进程。jdk提供的一个查看当前java进程的工具, JVM Process Status Tool
jinfo -flags {进程号}:jinfo 命令可以用来查看 Java 进程运行的 JVM 参数,; -flags 可以打印虚拟机标识。
jinfo -flags 29624
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=255852544 -XX:MaxHeapSize=4087349248 -XX:MaxNewSize=1362100224-XX:MinHeapDeltaBytes=524288 -XX:NewSize=84934656 -XX:OldSize=170917888 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops-XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC Command line: -javaagent:C:\ProgramFiles\JetBrains\IntelliJ_IDEA_Community_Edition_2021.2.2\lib\idea_rt.jar=53029:C:\ProgramFiles\JetBrains\IntelliJ_IDEA_Community_Edition_2021.2.2\bin -Dfile.encoding=UTF-8
3、jstat
jstat -gc ${pid} 500 —》每500ms刷新一下 pid 进程号
jstat -gc 29624 500
4、jstack ${pid}
把进程号 pid下的 所有线程的调用栈打出来
可以排查有没有死锁
5、jmap 查询堆内存里对象占用的比重、并可用于产生堆存储文件
- jmap -histo ${pid} | head -20 :每种类型的class占用的内存&对象数量
- jmap会让整个JVM卡死,不能在生产直接使用
- jmap -dump:format=b,file=helen.hprof ${pid} 产生堆内存存储文件(把JVM整个堆转成一个文件),可用于图形界面工具分析,如Java VisualVM(JDK自带Java\jdk1.8.0_144\bin)
看到 有些对象一直 回收不掉,java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask、CardInfo
侵删。