问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

使用JDK自带工具进行JVM内存分析之旅

创作时间:
2025-03-12 06:00:46
作者:
@小白创作中心

使用JDK自带工具进行JVM内存分析之旅

引用
1
来源
1.
https://cloud.tencent.com/developer/article/2410627

JVM内存分析是排查和预防Java应用程序中内存问题的重要手段。通过使用JDK自带的工具,如jps、jcmd、jstat、jstack和jmap,可以全面了解JVM的运行状态,诊断性能问题,并解决内存相关的错误。本文将详细介绍这些工具的使用方法及其应用场景。

JVM内存分析的重要性

进行JVM内存分析可以排查存在和潜在的问题。通过借助JDK自带的常用工具,可以分析大概可能的问题定位以及确定优化方向。

JVM内存分析有很多好处:

  • 内存泄漏排查:JVM内存泄漏是指应用程序中的对象占用的内存无法被垃圾回收器释放,导致内存占用持续增长,最终耗尽可用内存。通过内存分析工具,可以检测到哪些对象占用了大量内存且无法被释放,进而定位到可能存在内存泄漏的代码。

  • 内存优化:合理优化JVM内存配置可以提高应用程序的性能和稳定性。通过分析应用程序的内存使用情况,可以调整堆内存大小、永久代(如果是旧版Java)大小、新生代与老年代比例等参数,以减少垃圾回收频率,降低内存占用。

  • 性能调优:内存分析也有助于发现内存中的瓶颈,如频繁的Full GC(全局垃圾回收)导致的停顿时间过长。通过调整垃圾回收器类型、GC算法、堆内存大小等参数,可以改善应用程序的性能表现。

  • 异常分析:当应用程序出现内存相关的异常,如OutOfMemoryError(内存溢出错误)时,通过分析内存使用情况可以找到导致异常的根本原因,例如某个模块或对象占用了过多内存。

  • 容量规划:对于大型应用程序或者需要长时间运行的系统,进行内存分析可以帮助进行容量规划,确保系统具有足够的内存资源支持应用程序的正常运行。

一次JVM内存分析之旅

当需要进行JVM内存分析时,结合使用jps、jcmd、jstat、jstack和jmap可以提供全面的诊断信息。下面是一般的步骤:

  1. 使用jps查看Java进程的PID

    jps -l
    

    这将列出所有Java进程的PID和主类名。

  2. 使用jcmd执行一些诊断命令

    jcmd <PID> VM.flags
    jcmd <PID> VM.system_properties
    

    这些命令可以显示JVM的启动参数和系统属性,帮助了解JVM的配置。

  3. 使用jstat监视JVM内存和垃圾回收情况

    jstat -gc <PID> 5000 10
    

    这将持续输出JVM的垃圾回收情况,包括各个堆区的使用情况、GC时间等。

  4. 使用jstack生成线程堆栈信息

    jstack <PID>
    

    查看线程堆栈信息,以检查是否存在死锁或其他线程相关的问题。

  5. 使用jmap生成堆转储文件

    jmap -dump:file=heapdump.hprof <PID>
    

    这将生成一个名为heapdump.hprof的堆转储文件,可以用于进一步分析内存使用情况,查找内存泄漏等问题。

  6. 分析堆转储文件

    使用工具如Eclipse Memory Analyzer (MAT)或者VisualVM来分析生成的堆转储文件,查找内存泄漏、大对象、无用对象等问题。

通过结合使用这些工具,可以全面地了解JVM运行时的状态,诊断性能问题,以及解决内存相关的错误。

jps命令详解

jps是JDK提供了一个用于列出Java虚拟机进程的命令行工具。它通常用于查看当前系统中正在运行的Java进程的PID(进程标识符)以及对应的主类名。

下面是jps命令的使用方法:

jps [options] [hostid]

其中,options是一些可选的参数,hostid是可选的主机标识符。常用的选项包括:

  • -q:仅显示进程的PID,不显示对应的主类名。
  • -m:显示传递给主类的参数。
  • -l:显示主类的全限定名,通常用于区分具体的Java应用程序。
  • -v:显示传递给JVM的参数。

例如,要显示当前系统中所有Java进程的PID和对应的主类名,可以直接运行jps命令:

jps

如果要仅显示PID,可以使用-q选项:

jps -q

要显示主类的全限定名,可以使用-l选项:

jps -l

如果要显示传递给主类的参数,可以使用-m选项:

jps -m

如果要显示传递给JVM的参数,可以使用-v选项:

jps -v

jcmd命令详解

jcmd命令是Java 8新增的命令,可以执行多种JVM监控和诊断任务。例如,可以使用jcmd <pid> VM.flags查看JVM启动参数,或者使用jcmd <pid> Thread.print打印线程堆栈信息。

下面是jcmd命令的基本使用方法:

jcmd <PID | main class> <command> [options]

其中:

  • <PID | main class>:要操作的Java进程的PID(进程标识符)或者主类名。如果提供了PID,则直接操作对应的Java进程;如果提供了主类名,则jcmd会尝试找到匹配的Java进程并执行相应的命令。
  • <command>:要执行的诊断命令。
  • [options]:可选的命令参数。

常用的jcmd命令包括:

  • help:显示jcmd支持的命令列表,以及每个命令的简要描述。
  • VM.version:显示JVM的版本信息。
  • VM.flags:显示JVM的启动参数。
  • VM.system_properties:显示JVM的系统属性。
  • Thread.print:打印Java进程中所有线程的堆栈信息。
  • GC.run:执行一次垃圾回收。
  • GC.heap_dump:生成Java堆转储文件(heap dump)。

举例来说,如果要打印指定Java进程的线程堆栈信息,可以使用以下命令:

jcmd <PID> Thread.print

如果要执行一次垃圾回收,可以使用以下命令:

jcmd <PID> GC.run

如果要生成Java堆转储文件,可以使用以下命令:

jcmd <PID> GC.heap_dump <filename>

jstat命令详解

jstat命令可以监视JVM内存、垃圾回收等情况。例如,可以使用jstat -gc <pid>查看垃圾回收统计信息,或者使用jstat -gcutil <pid>查看垃圾回收统计信息及内存使用情况。

下面是jstat的基本使用方法:

jstat [options] <PID> [interval [count]]

其中:

  • [options]:可选的命令选项,用于指定要监视的数据类型和格式。
  • <PID>:要监视的Java进程的PID(进程标识符)。
  • [interval]:可选参数,指定输出统计信息的时间间隔(以毫秒为单位)。如果省略,则默认为每秒一次。
  • [count]:可选参数,指定输出统计信息的次数。如果省略,则默认为无限次输出。

常用的jstat命令选项包括:

  • -class:显示类加载、卸载信息以及类加载器的状态。
  • -gc:显示垃圾回收相关的信息,包括各个代的使用情况、GC时间等。
  • -compiler:显示即时编译器(JIT)的编译统计信息。
  • -gccapacity:显示各个堆区的容量及使用情况。
  • -gcutil:显示各个堆区的使用情况,以百分比表示。
  • -gccause:显示导致最近一次GC的原因。
  • -printcompilation:打印方法的即时编译(JIT)信息。

举例来说,要查看Java进程的类加载情况,可以使用以下命令:

jstat -class <PID>

如果想要每隔5秒输出一次类加载信息,共输出10次,可以使用以下命令:

jstat -class <PID> 5000 10

jstat只能查看当前的GC信息,查看GC日志更适合线上环境的做法是在启动JVM时加上-XX:+PrintGCDetails -Xloggc:/path/to/gc.log(JDK1.8以下)或者-Xlog:gc*:file=/path/to/gc.log(JDK9+)参数,将生成的GC日志文件放到GCViewer、GCeasy(需注册)进行分析。

jstack命令详解

jstack命令用于生成Java线程转储快照,可以用于分析线程状态、死锁等问题。例如,可以使用jstack <pid>打印线程堆栈信息,或者使用jstack -l <pid>打印线程堆栈信息及锁信息。

下面是jstack命令的基本使用方法:

jstack [options] <PID>

其中:

  • [options]:可选的命令选项,用于指定输出的格式等。
  • <PID>:要生成线程堆栈信息的Java进程的PID(进程标识符)。

常用的jstack命令选项包括:

  • -l:长列表格式,显示关于锁的附加信息,如拥有者和等待队列。
  • -F:当正常输出的jstack命令不起作用时,强制生成线程堆栈信息。这在Java进程没有响应时可能会很有用,但可能会导致进程暂停一段时间。
  • -m:显示Java和本地方法的堆栈跟踪,而不仅仅是Java堆栈跟踪。
  • -h:显示帮助信息。

举例来说,要生成指定Java进程的线程堆栈信息,可以使用以下命令:

jstack <PID>

如果想要输出长列表格式的线程堆栈信息,可以使用-l选项:

jstack -l <PID>

如果Java进程没有响应,可以使用-F选项强制生成线程堆栈信息:

jstack -F <PID>

jmap命令详解

异常没有发生定位异常代码,需要通过jmap生成dump文件。然后将其导入到MAT中进行分析。以下是生成堆转储文件的步骤:

  1. 确定Java进程ID:首先,需要确定正在运行的Java进程的进程ID(PID)。可以使用jps命令查看正在运行的Java进程及其PID。

  2. 生成堆转储文件:使用jmap命令生成堆转储文件。命令格式如下:

    jmap -dump:file=<文件路径> <PID>
    

    例如,要生成名为heapdump.hprof的堆转储文件,可以执行以下命令:

    jmap -dump:file=heapdump.hprof <PID>
    

    这将在当前工作目录下生成一个名为heapdump.hprof的堆转储文件。

  3. 导入堆转储文件到MAT:将生成的堆转储文件导入到MAT中进行分析。打开MAT,然后选择File -> Open Heap Dump,然后选择生成的堆转储文件。

  4. 执行内存分析:一旦堆转储文件被导入到MAT中,就可以执行内存分析,按照前面提到的步骤来查找内存问题。

通过这些步骤可以手动生成堆转储文件并使用MAT进行分析,即使没有在OutOfMemoryError发生时自动生成堆转储文件也可以找到问题所在。更适合线上环境的做法是在启动JVM时加上-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof参数,这样当发生OutOfMemoryError时,JVM会自动生成堆转储文件。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号