未读代码 未读代码
首页
  • Java 18 新功能介绍
  • Java 17 新功能介绍
  • Java 16 新功能介绍
  • Java 15 新功能介绍
  • Java 14 新功能介绍
  • Java 8 新特性

    • Java 8 Lambda 表达式
    • Java 8 Stream 流式操作
    • Java 8 时间处理介绍
    • Java 8 Optional 介绍
  • Java 开发工具
Java 源码分析
Spring Boot 系列
  • Arthas 问题定位
  • JMH 基准测试
GitHub (opens new window)
首页
  • Java 18 新功能介绍
  • Java 17 新功能介绍
  • Java 16 新功能介绍
  • Java 15 新功能介绍
  • Java 14 新功能介绍
  • Java 8 新特性

    • Java 8 Lambda 表达式
    • Java 8 Stream 流式操作
    • Java 8 时间处理介绍
    • Java 8 Optional 介绍
  • Java 开发工具
Java 源码分析
Spring Boot 系列
  • Arthas 问题定位
  • JMH 基准测试
GitHub (opens new window)
  • Java 性能分析

    • Java 性能分析与优化导读
    • Arthas - Java 线上问题定位处理的终极利器
    • Java 中的监控与管理原理概述
    • JMX 监控和管理 Java 程序
    • JMC 使用教程
      • JMC 介绍
      • JMC 测试环境准备
        • 测试代码准备
      • JMC 概览
      • JMC 触发器
      • JMC 分析内存
      • JMC 分析CPU
      • JMC 分析死锁
    • JFR 使用教程
    • JMH - Java 代码性能基准测试
    • Async-Profiler - Java 火焰图性能分析工具
    • Java 中的5个代码性能提升技巧,最高提升近10倍
  • Java 性能分析
  • Java 性能分析
程序猿阿朗
2023-03-15

JMC 使用教程

# JMC 介绍

Java Mission Control(JMC)是一个强大的 Java 应用程序分析工具,从 2018 年开始,JMC 被 Oracle 开源作为独立工具发布。JMC 是一款可以用于管理、监听、分析以及排除 Java 故障的高级工具,使用 JMC 可以对代码性能、内存分配、GC 延迟、CPU 使用等情况进行低开销的、高效且详细的分析。

JMC

截止本文编写时间,JMC 最新版本8.3 .

开源地址:https://github.com/openjdk/jmc (opens new window)

Oracle 官方地址:https://www.oracle.com/java/technologies/jdk-mission-control.htmld

Oracle JMC 下载:https://www.oracle.com/java/technologies/javase/products-jmc8-downloads.html

# JMC 测试环境准备

下载安装 JMC 这里不做描述,根据自己的系统环境下载相应的 JMC 版本安装启动即可。有一点要注意的是,从 JMC 8.10 开始,所依赖的最低 JDK 版本为 JDK11,如果你是 JDK 8 环境,可以下载 JMC 8.0 版本。如果你所在的 JVM 环境为 32 位,那么应该使用 -Dcom.sun.management.jmxremote 参数来启动 JVM。

# 测试代码准备

在启动 JMC 之前,准备一段有很多问题的代码,这段代码的问题包括诸多问题。

文章测试代码地址:https://github.com/niumoo/JavaNotes/ (opens new window)

  1. CPU 使用过高

    通过不断地进行浮点运算来提高对 CPU 的消耗。

    /**
     * 消耗CPU的线程
     * 不断循环进行浮点运算
     */
    private static void cpuHigh() {
        Thread thread = new Thread(() -> {
            Thread.currentThread().setName("cpu_high_thread");
            while (true){
                double pi = 0;
                for (int i = 0; i < Integer.MAX_VALUE; i++) {
                    pi += Math.pow(-1, i) / (2 * i + 1);
                }
                System.out.println("Pi: " + pi * 4);
            }
        });
        thread.start();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
  2. 内存使用过高

    不断地生成 BigDecimal 数字添加到 List 来增加对内存的使用。

    /**
     * 不断新增 BigDecimal 信息到 list
     */
    private static void allocate() {
        new Thread(()->{
            Thread.currentThread().setName("memory_allocate_thread");
            List<BigDecimal> list = new ArrayList<>();
            for (int i = 0; i < Integer.MAX_VALUE; i++) {
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                list.add(new BigDecimal(i));
            }
        }).start();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
  3. 线程池堵塞

  4. 死锁

    线程 dead_thread_A 与 线程 dead_thread_B 互相等待造成死锁。

    /**
     * 死锁线程
     * 线程 dead_thread_A 与 线程 dead_thread_B 互相锁死
     */
    private static void deadThread() {
        /** 创建资源 */
        Object resourceA = new Object();
        Object resourceB = new Object();
        // 创建线程
        Thread threadA = new Thread(() -> {
            Thread.currentThread().setName("dead_thread_A");
            synchronized (resourceA) {
                System.out.println(Thread.currentThread() + " get ResourceA");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resourceB");
                synchronized (resourceB) {
                    System.out.println(Thread.currentThread() + " get resourceB");
                }
            }
        });
    
        Thread threadB = new Thread(() -> {
            Thread.currentThread().setName("dead_thread_A");
            synchronized (resourceB) {
                System.out.println(Thread.currentThread() + " get ResourceB");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resourceA");
                synchronized (resourceA) {
                    System.out.println(Thread.currentThread() + " get resourceA");
                }
            }
        });
        threadA.start();
        threadB.start();
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43

# JMC 概览

启动测试代码后,启动 JMC 就可以在左侧的 JMV 浏览器中看到当前机器所有的 JVM 进程,选择测试代码进行通过 MBean 服务器进行连接,然后可以看到概览界面。

JMC 概览

通过概览界面,可以看到进程的 JVM 内存使用情况,JVM CPU 使用情况,可以对进程的总体情况有一个初步的判断。

# JMC 触发器

JMC 触发器可以理解为一个 JVM 告警,可以对 JVM 进程的各种指标设置阈值,在超过指定阈值后可以收到告警提示,对进程异常情况监控十分方便。

JMC 触发器

这里对 CPU 占用率和死锁线程数进行监控,由于问题代码的原因,很快就触发了告警。

JMC 触发器

通过弹窗告警可以看到告警原因,以及对应的类信息,但是这里目前还看不到告警的具体原因,也就是说比如 CPU 占用率过高,并不知道为什么 CPU 会使用过高。

# JMC 分析内存

通过内存页面可以看到堆内存分配情况,由于问题代码中再不断地分配 BigDecimal 对象,这里也可以看出 BigDecimal 对象占用了最多的内存。对分析内存过高情况有一定的帮助。

JMC 内存

如果想进一步分析内存占用来源,可以到线程页面,通过勾选分配复选框,可以看到哪个线程占用的内存最多,还可以看到线程的具体的调用堆栈。

JMC 线程

# JMC 分析CPU

线程页面勾选 CPU 概要分析可以查看占用 CPU 最高的线程,这里线程 cpu_high_thread 在不断地进行浮点计算,占用了较多的 CPU。

JMC 分析 CPU

# JMC 分析死锁

线程页面勾选死锁检测可以直接看到死锁线程信息,并且有具体的线程堆栈。

JMC 线程死锁

另外一种检查死锁的方式是直接打印线程信息,在线程信息的最后部分,会输出死锁线程信息。使用 JMC 可以通过诊断命令中的 Thread.print 命令来实现这个功能。

JMC 诊断命令

一如既往,文章测试代码地址:https://github.com/niumoo/JavaNotes/ (opens new window)

订阅

文章持续更新,订阅可以关注「 程序猿阿朗 」公众号或者未读代码博客。

文章作者: 程序猿阿朗
文章链接:https://www.wdbyte.com/java/performance/jmc.html
版权声明:本网站当前文章采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 未读代码!
#jmc
上次更新: 2023/03/15, 09:22:31
JMX 监控和管理 Java 程序
JFR 使用教程

← JMX 监控和管理 Java 程序 JFR 使用教程→

最近更新
01
JFR 使用教程
03-15
02
你好 ChatGPT, 帮我看下这段代码有什么问题?
02-14
03
如何搭建一个自己的音乐服务器
12-04
更多文章>

提示:评论前请刷新页面,否则评论的可能不是当前文章。

Theme by Vdoing | Copyright © 2018-2023 程序猿阿朗 | MIT License | 皖ICP备20000567号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式