【Java虚拟机】JVM常见诊断命令和调试工具

简介: 【Java虚拟机】JVM常见诊断命令和调试工具

1.JVM常用命令行参数jps和jinfo实操

  • 准备测试代码
/**
 * @author lixiang
 * @date 2023/5/4 20:53
 */
public class JVMTest {
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(1000000);
    }
}

(1)命令jps:全称 java process Status Tool, Java版的ps命令,查看java进程及其相关的信息的pid则可以用这个命令,和linux的ps类似

  • 格式: jps [options] [hostid]
  • 参数解释
  • -l:显示进程id,显示主类全名或这jar路径
  • -q : 显示进程id
  • -m : 显示进程id, 显示JVM启动时传递给main()的参数
  • -v : 显示进程id,显示JVM启动时显示指定的JVM参数
  • hostid : 主机或其他服务器ip
  • 常用案例
  • jps -l 输出jar包路径,类的全名

2505ee707d25440a91e16ee6aa862131.jpg

  • jps -v 输出JVM参数

342f469332fd486595347194f61af9bb.jpg

(2)命令jinfo:全称 Configuration Info for Java ,可以用来查看jvm参数和动态修改部分jvm参数的命令

  • 启动java程序,不会指定所有的Java虚拟机参数,如果开发人员想知道某一个具体的Java虚拟机参数的默认值则可以使用
  • 还可以在运行时修改部分参数,且立即生效,但注意并非所有参数都支持动态修改,被标记 manageable的才可以动态修改
  • 格式 jinfo [options]
  • 参数解释
  • no options :输出所有的系统属性和参数
  • -flag <具体参数> pid: 查看具体参数的值
  • -flag [+|-] : 打开或关闭参数
  • -flag = 设置参数值
  • -flags 打印所有参数
  • -sysprops 打印系统配置
  • 常用案例
  • jinfo -flags pid 查看曾经赋过值的参数值
  • a4828fb19d0c43e2b043301e3950cb69.jpg
  • jinfo -flag <具体参数> pid 查看具体参数的值

f4477536abb342d1b6fb49880e3d2605.jpg

  • jinfo 动态进行参数修改
  • 查看哪些可以动态修改参数 java -XX:+PrintFlagsFinal -version | grep manageable

028e9207aec84b72af045759c3110f6c.jpg

  • 修改方式
  • 布尔类型: jinfo -flag ±参数 pid
  • 非布尔类型: jinfo -flag 参数名=参数值 pid
  • jinfo -flag +HeapDumpAfterFullGC 11190

84c5906da35d470cbef782930cd0dc2c.jpg

2.JVM高频命令行参数jstat案例实操

(1)命令jstat:Java Virtual Machine statistics monitoring tool, 对Java应用程序的资源进行实时监控,包括堆和垃圾回收状况的监控

格式 jstat [-option] [vmid] [间隔时间/毫秒] [查询次数]

  • 参数选项
  • vmid:Virtual Machine ID( 进程的 pid)
  • interval:执行每次的间隔时间,单位为毫秒
  • count:用于指定输出多少次记录,缺省则会一直打印

option说明


-class 查看类加载情况的统计

-compiler 查看HotSpot中即时编译器编译情况的统计

-gc 查看JVM中堆的垃圾收集情况的统计

-gccapacity 查看新生代、老生代及持久代的存储容量情况

-gcmetacapacity 显示metaspace的大小

-gcnew 查看新生代垃圾收集的情况

-gcnewcapacity 用于查看新生代存储容量的情况

-gcold 查看老生代及持久代垃圾收集的情况

-gcoldcapacity 用于查看老生代的容量

-gcutil 显示垃圾收集信息

-gccause 显示垃圾回收的相关信息(通-gcutil),同时显示最后一次仅当前正在发生的垃圾收集的原因

-printcompilation 输出JIT编译的方法信息

常用命令


jstat -class pid 查看类加载情况的统计

Loaded:加载类的数量

Bytes:加载类的size,单位为Byte

Unloaded:卸载类的数目

Bytes:卸载类的size,单位为Byte

Time:加载与卸载类花费的时间

355ac5a951a64c819ce8b897dacbfda8.jpg


jstat -gc pid 查看JVM中堆的垃圾收集情况的统计,输出实际的值

S0C:年轻代中第一个survivor(幸存区)的容量 (字节)

S1C:年轻代中第二个survivor(幸存区)的容量 (字节)

S0U:年轻代中第一个survivor(幸存区)目前已使用空间 (字节)

S1U:年轻代中第二个survivor(幸存区)目前已使用空间 (字节)

EC:年轻代中Eden(伊甸园)的容量 (字节)

EU:年轻代中Eden(伊甸园)目前已使用空间 (字节)

OC:Old代的容量 (字节)

OU:Old代目前已使用空间 (字节)

MC:metaspace(元空间)的容量 (字节)

MU:metaspace(元空间)目前已使用空间 (字节)

CCSC:当前压缩类空间的容量 (字节)

CCSU:当前压缩类空间目前已使用空间 (字节)

YGC:从应用程序启动到采样时年轻代中gc次数

YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)

FGC:从应用程序启动到采样时Full GC 的次数

FGCT:从应用程序启动到采样时Full GC 所用时间(s)

GCT:从应用程序启动到采样时垃圾回收消耗总时(s)

72b4c53bbfde45e698913fab560cb546.jpg


jstat -gcutil pid 时间间隔 打印次数 显示垃圾收集信息,和-gc类似,不过是百分比展示, 每隔2000毫秒打印一次,打印3次


S0 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比


S1 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比


E 年轻代中Eden(伊甸园)已使用的占当前容量百分比


O 老年代已使用的占当前容量百分比


M 元数据区已使用的占当前容量百分比


CCS 压缩使用百分比


YGC 年轻代垃圾回收次数


YGCT 年轻代垃圾回收消耗时间


FGC Full GC垃圾回收次数


FGCT Full GC垃圾回收消耗时间


CGC: 并发GC次数


CGCT: 并发GC总耗时


GCT 垃圾回收消耗总时间


663098cbd5b04ae1b779fbefafd7cddb.jpg


jstat -gccause pid 显示垃圾回收的相关信息,最后一次或当前正在发生的垃圾回收的诱因

d6915ed6018e40e2a357d8d56caf58b9.jpg


LGCC:最后一次GC原因,常见是 Allocation Failure 申请内存失败

GCC:当前GC原因(No GC 为当前没有执行GC)

3.JVM命令jstack讲解及案例分析

(1)命令 jstack:Java堆栈跟踪工具, 可以打印出Java应用程序中所有线程的堆栈信息,包括线程状态、调用栈信息、锁信息等

用于诊断线程死锁、死循环、内存泄漏等问题


格式 jstack [ options ] pid


option 参数说明


-l 打印关于锁的附加信息,如持有锁的线程、等待锁的线程等

常用案例


jstack -l pid 查看线程堆栈信息

开头是线程名称,即main 线程,后面的为线程信息,线程状态如下

NEW

RUNNABLE

BLOCKED#进入synchronized之前

WAITING#已经进入synchronized,调用了wait()

TIMED_WAITING#已经进去synchronized,调用了sleep()

TERMINATED#线程结束

#1 表示当前线程ID,从 main线程开始,JVM 根据线程创建的顺序为线程编号

prio 是priority优先级的缩写,代表当前线程的优先级,范围为[1-10]默认为 5,数值越低越优先获取到计算资源

cpu=60.91ms 表示进程在CPU上的运行时间为60.91毫秒

指的是进程实际占用CPU的时间,

elapsed=13.05s 表示进程已经运行13.05秒

进程从开始运行到当前时刻所经过的时间,包括进程等待时间和实际运行时间

os_prio为线程对应系统的优先级

tid 表示Java内的线程ID,同样在Thread类中(可以不管)

nid

本地线程编号NativeID的缩写, 表示操作系统级别的线程ID,

对应JVM 虚拟机中线程映射在操作系统中的线程编号,是十六进制


6cc3a97a9bff4566a52e31c02fb26270.jpg

(2)案例分析


生产环境JVM中,会出现由于代码问题导致CPU占用过高,需要诊断出来具体是哪个java代码导致

分析CPU占用过高的java线程案例

测试代码

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CpuTest {
    private static ExecutorService executorService = Executors.newFixedThreadPool(5);
    public static void main(String[] args) {
        Task task1 = new Task();
        Task task2 = new Task();
        executorService.execute(task1);
        executorService.execute(task2);
    }
    public static Object lock = new Object();
    static class Task implements Runnable{
        @Override
        public void run() {
            synchronized (lock){
                long sum = 0L;
                while (true){
                    sum += 1;
                }
            }
        }
    }
}
  • 运行代码,top命令找出CPU过高的进程。

image.jpeg

  • 当前这个java进程CPU的使用率已经到达百分之99,确认进程ID
  • 将十进制的进程ID转化成十六进制 printf "%x\n" 线程id

e6507e8cdb204aefa70b80922208fdfe.jpg

  • 定位问题线程堆栈信息,一般会生成快照到文本文件里面进行分析 jstack -l [PID] >/tmp/log.txt
  • 查看log.txt文件内容,这里存在一个死锁

image.jpeg

4.新版JDK11命令jmap案例实操

(1)命令jmap:Memory Map for Java , 用于生成Java堆转储快照(heap dump),分析Java应用程序的内存使用情况

包括 堆的使用情况、对象的数量和类型、每个对象的大小、对象的地址、对象的引用关系等


格式 jmap [option] pid


option参数说明


-heap: 打印java heap 摘要


-histo[:live] : 打印堆中的java对象统计信息


-clstats : 打印类加载器统计信息


-finalizerinfo:打印在f-queue中等待执行finalizer方法的对象


-dump: 生成java堆的dump文件, dump-options 参数如下


live : 只转储存活的对象,如果没有指定则转储所有对象

format=b: 二进制格式

file=[Path] : 将文件转储到指定文件中

常用案例


jmap -heap 进程id 查看堆信息, 这个命令会让JVM 是暂停服务的,所以对线上的运行会产生影响,不推荐该方式


JDK9 及以上版本使用jmap -heap pid命令查看当前heap使用情况时,发现报错,提示需要使用jhsdb jmap来替代,我本地是JDK11


9a91e476aa414e4d8b1699f7a172d478.jpg

jhsdb jmap --pid 进程id --heap

[mac@localhost lixiang ~]# jhsdb jmap --pid 3110235  --heap
Attaching to process ID 3110235, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0.8+10-LTS
using thread-local object allocation.
Garbage-First (G1) GC with 4 thread(s)
Heap Configuration:
   MinHeapFreeRatio         = 40 #最小堆空闲比例。
   MaxHeapFreeRatio         = 70 #最大堆空闲比例。
   MaxHeapSize              = 1979711488 (1888.0MB) #最大堆大小。
   NewSize                  = 1363144 (1.2999954223632812MB) #新生代大小。
   MaxNewSize               = 1186988032 (1132.0MB) #最大新生代大小。
   OldSize                  = 5452592 (5.1999969482421875MB) #老年代大小。
   NewRatio                 = 2 #新生代和老年代的比例。
   SurvivorRatio            = 8 #新生代中eden区和survivor区的比例。
   MetaspaceSize            = 21807104 (20.796875MB) #元空间大小。
   CompressedClassSpaceSize = 1073741824 (1024.0MB) #压缩类空间大小。
   MaxMetaspaceSize         = 17592186044415 MB  #最大元空间大小。
   G1HeapRegionSize         = 1048576 (1.0MB) //G1垃圾收集器每个Region大小
Heap Usage:
G1 Heap:
   regions  = 1888  #堆中区域数量
   capacity = 1979711488 (1888.0MB) #堆的总容量
   used     = 12332544 (11.76123046875MB)  #堆已使用的容量
   free     = 1967378944 (1876.23876953125MB) #堆未使用的容量
   0.6229465290651484% used #堆的使用率。
G1 Young Generation:  #G1垃圾收集器中的年轻代。
Eden Space: #年轻代中的Eden区域。
   regions  = 8
   capacity = 75497472 (72.0MB)
   used     = 8388608 (8.0MB)
   free     = 67108864 (64.0MB)
   11.11111111111111% used
Survivor Space: #年轻代中的survivor区域
   regions  = 2
   capacity = 2097152 (2.0MB)
   used     = 2097152 (2.0MB)
   free     = 0 (0.0MB)
   100.0% used
G1 Old Generation: #G1垃圾收集器中的老年代。
   regions  = 2
   capacity = 46137344 (44.0MB)
   used     = 1846784 (1.76123046875MB)
   free     = 44290560 (42.23876953125MB)
   4.002796519886363% used #老年代的使用率。

5.JVM可视化分析JConsole案例实操

  • Java Monitoring and Management Console,虚拟机自带的一种监控和管理工具
  • 可以通过图形化界面展示Java应用程序的运行状态和性能指标,包括内存使用情况、线程状态、类加载情况、GC情况等

JConsole的主要用途包括:

监控Java应用程序的运行状态

实时展示Java应用程序的运行状态和性能指标,包括CPU使用率、内存使用情况、线程状态、类加载情况、GC情况

诊断Java应用程序的问题

提供详细的诊断信息,帮助开发人员分析和解决Java应用程序的问题,如内存泄漏、死锁等。

监控远程Java应用程序

可以通过JMX(Java Management Extensions)协议监控远程Java应用程序,远程管理和监控Java应用程序。

执行JMX操作

JConsole可以执行JMX操作,如调用Java应用程序中的方法、修改Java应用程序的配置等。

使用方式 命令行输入 jconsole 启动即可,选择自己的类进程

72fabf4d1f01472fb6a6a6f0324ef10e.jpg

43460a1bbd064d4c8af69d2d6d784317.jpg

3943d1d07c084f13943f949805843020.jpg

69ee7bab5cdf4aa5843dd0cf7d8c5e4c.jpg


相关文章
|
2月前
|
存储 算法 Java
惊!Java程序员必看:JVM调优揭秘,堆溢出、栈溢出如何巧妙化解?
【8月更文挑战第29天】在Java领域,JVM是代码运行的基础,但需适当调优以发挥最佳性能。本文探讨了JVM中常见的堆溢出和栈溢出问题及其解决方法。堆溢出发生在堆空间不足时,可通过增加堆空间、优化代码及释放对象解决;栈溢出则因递归调用过深或线程过多引起,调整栈大小、优化算法和使用线程池可有效应对。通过合理配置和调优JVM,可确保Java应用稳定高效运行。
113 4
|
21天前
|
存储 缓存 监控
【Java面试题汇总】JVM篇(2023版)
JVM内存模型、双亲委派模型、类加载机制、内存溢出、垃圾回收机制、内存泄漏、垃圾回收流程、垃圾回收器、G1、CMS、JVM调优
【Java面试题汇总】JVM篇(2023版)
|
1月前
|
安全 前端开发 Java
浅析JVM invokedynamic指令与Java Lambda语法的深度融合
在Java的演进历程中,Lambda表达式无疑是Java 8引入的一项革命性特性,它极大地简化了函数式编程在Java中的应用,使得代码更加简洁、易于阅读和维护。而这一切的背后,JVM的invokedynamic指令功不可没。本文将深入探讨invokedynamic指令的工作原理及其与Java Lambda语法的紧密联系,带您领略这一技术背后的奥秘。
19 1
|
2月前
|
机器学习/深度学习 人工智能 算法
探索人工智能在医疗诊断中的应用与挑战Java编程中的对象和类:基础与实践
【8月更文挑战第27天】随着人工智能(AI)技术的飞速发展,其在医疗领域的应用日益广泛。本文深入探讨了AI技术在医疗诊断中的具体应用案例,包括图像识别、疾病预测和药物研发等方面,并分析了当前面临的主要挑战,如数据隐私、算法偏见和法规限制等。文章旨在为读者提供一个全面的视角,理解AI在改善医疗服务质量方面的潜力及其局限性。
|
2月前
|
Java
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
【Azure 应用服务】如何查看App Service Java堆栈JVM相关的参数默认配置值?
|
2月前
|
C# 开发者 Windows
震撼发布:全面解析WPF中的打印功能——从基础设置到高级定制,带你一步步实现直接打印文档的完整流程,让你的WPF应用程序瞬间升级,掌握这一技能,轻松应对各种打印需求,彻底告别打印难题!
【8月更文挑战第31天】打印功能在许多WPF应用中不可或缺,尤其在需要生成纸质文档时。WPF提供了强大的打印支持,通过`PrintDialog`等类简化了打印集成。本文将详细介绍如何在WPF应用中实现直接打印文档的功能,并通过具体示例代码展示其实现过程。
135 0
|
2月前
|
数据库 C# 开发者
WPF开发者必读:揭秘ADO.NET与Entity Framework数据库交互秘籍,轻松实现企业级应用!
【8月更文挑战第31天】在现代软件开发中,WPF 与数据库的交互对于构建企业级应用至关重要。本文介绍了如何利用 ADO.NET 和 Entity Framework 在 WPF 应用中访问和操作数据库。ADO.NET 是 .NET Framework 中用于访问各类数据库(如 SQL Server、MySQL 等)的类库;Entity Framework 则是一种 ORM 框架,支持面向对象的数据操作。文章通过示例展示了如何在 WPF 应用中集成这两种技术,提高开发效率。
41 0
|
2月前
|
缓存 前端开发 Java
浅析JVM invokedynamic指令与Java Lambda语法
【8月更文挑战第27天】在Java的演进历程中,invokedynamic指令的引入和Lambda表达式的出现无疑是两大重要里程碑。它们不仅深刻改变了Java的开发模式和性能表现,还极大地推动了Java在函数式编程和动态语言支持方面的进步。本文将从技术角度浅析JVM中的invokedynamic指令及其与Java Lambda语法的紧密联系。
41 0
|
2月前
|
安全 前端开发 Java
【JVM 探秘】ClassLoader 类加载器:揭秘 Java 类加载机制背后的秘密武器!
【8月更文挑战第25天】本文全面介绍了Java虚拟机(JVM)中的类加载器,它是JVM的核心组件之一,负责将Java类加载到运行环境中。文章首先概述了类加载器的基本工作原理及其遵循的双亲委派模型,确保了核心类库的安全与稳定。接着详细阐述了启动、扩展和应用三种主要类加载器的层次结构。并通过一个自定义类加载器的例子展示了如何从特定目录加载类。此外,还介绍了类加载器的完整生命周期,包括加载、链接和初始化三个阶段。最后强调了类加载器在版本隔离、安全性和灵活性方面的重要作用。深入理解类加载器对于掌握JVM内部机制至关重要。
58 0
|
2月前
|
运维 监控 Java
【JVM 调优秘籍】实战指南:JVM 调优参数全解析,让 Java 应用程序性能飙升!
【8月更文挑战第24天】本文通过一个大型在线零售平台的例子,深入探讨了Java虚拟机(JVM)性能调优的关键技术。面对应用响应延迟的问题,文章详细介绍了几种常用的JVM参数调整策略,包括堆内存大小、年轻代配置、垃圾回收器的选择及日志记录等。通过具体实践(如设置`-Xms`, `-Xmx`, `-XX:NewRatio`, `-XX:+UseParallelGC`等),成功降低了高峰期的响应时间,提高了系统的整体性能与稳定性。案例展示了合理配置JVM参数的重要性及其对解决实际问题的有效性。
55 0
下一篇
无影云桌面