目录
- JFR和JMC
- 启动飞行记录
- 用JFR对比不同GC器
- 运行结果
- 记录结果
- GC配置
- GC Summary
- 垃圾收集
JFR和JMC
JFR全称为Java Flight Recorder,即Java飞行记录器
JMC全称为JDK Mission Control,即JDK任务控制
先贴一段官网的简介:
Java Flight Recorder and JDK Mission Control together create a complete tool chain to continuously collect low level and detailed runtime information enabling after-the-fact incident analysis.
Java飞行记录器和JDK任务控制一起创建了一个完整的工具链,以持续收集低级别和详细的运行时信息,从而支持事后事件分析。
Java Flight Recorder is a profiling and event collection framework built into the Oracle JDK.
It allows Java administrators and developers to gather detailed low level information about how the Java Virtual Machine (JVM) and the Java application are behaving.
Java飞行记录器是一个内置在Oracle JDK中的分析和事件收集框架。
它允许Java管理员和开发人员收集关于Java虚拟机(JVM)和Java应用程序如何行为的详细底层信息。
JDK Mission Control (JMC) is a production-time profiling and diagnostics tool.
It includes tools to monitor and manage your Java application with a very small performance overhead, and is suitable for monitoring applications running in production.
JDK Mission Control is an advanced set of tools that enables efficient and detailed analysis of the extensive of data collected by Java Flight Recorder.
The tool chain enables developers and administrators to collect and analyze data from Java applications running locally or deployed in production environments.
JDK任务控制(JMC)是一个生产时间分析和诊断工具。
它包括用于监控和管理Java应用程序的工具,并且适用于监控在生产中运行的应用程序。
JDK任务控制是一套先进的工具,能够对Java飞行记录器收集的大量数据进行高效和详细的分析。
该工具链使开发人员和管理员能够从本地运行或部署在生产环境中的Java应用程序中收集和分析数据。
可见,JFR用来记录和收集Java运行时的数据和事件;JMC是分析和诊断工具,可用来打开和分析JFR文件
启动飞行记录
- 官网下载JMC8.3.1
- 启动一个Java程序
- 打开jmc.exe,选择一个Java程序->右键->启动飞行记录
可选择记录时间,默认是1分钟
可以看到正在记录,并有倒计时
- 记录完成后,会生成.jfr后缀文件,可用JMC打开
用JFR对比不同GC器
代码如下:
public class Test {
public static void main(String[] args) {
// 记录线程编号
AtomicInteger threadNo = new AtomicInteger(1);
// 主线程池
ScheduledExecutorService gcExecutor = Executors.newScheduledThreadPool(5);
// 监控主线程池的线程池,用来停止主线程池
ExecutorService monitorExecutor = Executors.newSingleThreadExecutor();
long start = System.currentTimeMillis();
monitorExecutor.execute(() -> {
// 主线程池运行70秒
while (System.currentTimeMillis() - start < 70 * 1000) {
try {
TimeUnit.MILLISECONDS.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
// 停止主线程池
gcExecutor.shutdownNow();
});
monitorExecutor.shutdown();
for (int i = 0; i < 1_000_000; i++) {
gcExecutor.execute(() -> {
Thread.currentThread().setName("-gc-thread-" + threadNo.getAndIncrement());
System.out.println(Thread.currentThread().getName() + "\tstart");
// 疯狂创建对象,触发GC
for (int k = 0; k < 1_000_000; k++) {
if (gcExecutor.isTerminated()) {
return;
}
new GcObj(k);
}
System.out.println(Thread.currentThread().getName() + "\tfinish");
});
}
while (!gcExecutor.isTerminated()) {
}
System.out.println(System.currentTimeMillis() - start + "ms");
}
@AllArgsConstructor
private static class GcObj {
private final int i;
}
}
分别用下面3种组合运行程序,启动飞行记录:
- JDK:1.8.0_371,GC:CMS
- JDK:17.0.7,GC:G1,-XX:+UseG1GC
- JDK:17.0.7,GC:ZGC,-XX:+UseZGC
运行结果
可见,CMS在70秒内只处理了3W+个线程,而G1和ZGC则可以处理56W+个线程,CMS在GC的STW上消耗了大量时间
记录结果
GC配置
GC Summary
可见,CMS的GC时间=STW时间,G1和ZGC的STW时间远小于GC时间,也验证了存在与应用程序并行的GC阶段,效率大大提高
垃圾收集
Allocation Failure
Ergonomics
G1 Evacuation Pause
G1 Humongous Allocation
Warmup
作者:曼特宁