关于jvm:JDK中自带的JVM分析工具

34次阅读

共计 4289 个字符,预计需要花费 11 分钟才能阅读完成。

内存溢出,妥妥的名局面;

一、业务背景

对于分布式架构中的文件服务来说,因为波及大量的 IO 流操作,很容易引发 JVM 的相干异样,尤其是内存溢出的问题;

在最近的一次版本迭代中,实在的业务解决场景和上述简直统一,因为在文件服务中增加批量解决的动作,间接唤醒了暗藏许久的 BUG,就是最常见的内存溢出;

问题的起因:在 word 文档实现内容辨认后,转换为 pdf 文件,而后进行页面宰割转为一组图片,在这个简单并且超长的流程中存在一个数组容器未销毁;

解决的形式:剖析 JVM 的 dump 文件,定位 OOM 问题引发的根本原因,联合文件服务的异样日志剖析,增加资源的开释动作,从而解决问题;

二、Jdk-Bin 目录

对于相当一部分老手来说,看到 JVM 的问题都是 Bug 不知所起一脸懵的,其实这种心态大可不必,从职场几年的开发教训上看,JVM 的问题大抵分为两种:

  • 开发轻松解决:能够降级内存资源或者调整调配,又或者对程序优化,实现相干资源的治理和开释,这是最罕用的伎俩;
  • 轻松解决开发:因为经验不足,程序呈现重大 BUG 导致 JVM 异样,进而引起系列的连锁反应,这种不会绝地反弹,只有一地鸡毛;

在解决惯例的 JVM 异样时,通常依赖 JDK 中根底工具即可实现问题的定位,从而进行剖析和解决,不过这些须要对根底工具纯熟应用才行,而很多 JDK 本身的能力又是常常被疏忽的;

在 jdk 的 bin 目录中,有很多自带工具能够用于对 JVM 的剖析;

上述是基于 jdk1.8 的目录,外面有很多开发常常用到命令,上面围绕一个微服务的启动和运行,来看看基于 JDK 中自带 JVM 工具的用法;

三、命令行工具

1、jps 命令

jps:虚拟机过程状态工具,该命令在 Java 环境部署和服务启动查看时常常用到,首先在本地启动一个 facade 门面微服务,而后在命令行中执行查问;

  • jps:命令默认输入的是过程 ID 和利用主类的名称;
  • -l:输入过程 ID 和利用主类的残缺门路;
  • -v:输入向 jvm 传递的参数,此处展现为 idea 中显式配置的 VM-options 参数,其余内容自行查看即可;
  • -m:输入向 main 办法传递的参数,服务启动前能够在 idea 的 Program-arguments 配置;
$ jps
1281 FacadeApp

$ jps -l
1281 com.explore.facade.FacadeApp

$ jps -v
1281 FacadeApp -Xms128m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m

$ jps -m
1281 FacadeApp hello,main-method

2、jinfo 命令

jinfo:在命令前面带 pid 过程号,能够输入指定过程的配置信息,在利用启动时通常不会指定过多的配置参数,就能够应用该命令查问很多参数的默认值;该命令还能够在运行时动静调整局部参数,只是很少被应用;

$ jinfo 1281            # 只粘贴个别参数
Java System Properties: # 零碎参数
    java.runtime.version=1.8.0_144-b01
    file.encoding=UTF-8
    sun.java.command=com.explore.facade.FacadeApp hello,main-method
    
VM Flags:               # 虚拟机参数
    -XX:InitialHeapSize=134217728 -XX:MaxHeapSize=268435456 -XX:MaxNewSize=267911168
    
VM Arguments:           # 运行时参数
    jvm_args: -Xms128m -Xmx256m -XX:MaxNewSize=256m -XX:MaxPermSize=256m
    java_command: com.explore.facade.FacadeApp hello,main-method

$ jinfo -sysprops 1281  # 只输入【Java System Properties】参数

$ jinfo -flags 1281     # 只输入【VM Flags】参数

3、jstat 命令

jstat:以指定的频率输入 JVM 的监控指标,下述命令输入内存占用和 GC 相干信息,每隔 3 秒输入一次,间断打印 5 次;因为这里只是启动一个简略的微服务,没有执行业务逻辑,所以各项指标比拟安稳;

$ jstat -gcutil 1281 3000 5
S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT   
0.00   0.00  57.97  64.16  92.82  88.75    3    0.028     9    0.516     -        -    0.544
0.00   0.00  57.97  64.16  92.82  88.75    3    0.028     9    0.516     -        -    0.544

该命令是比拟罕用的,这里各项指标的统计逻辑,在 tools.jar 包中有 jstat_options 参考文档,相对路径 sun/tools/jstat/resources/ 目录下;

option gcutil {
  column {
    header "^S0^"    /* Survivor 0 Space - Percent Used */
    data (1-((sun.gc.generation.0.space.1.capacity - sun.gc.generation.0.space.1.used)/sun.gc.generation.0.space.1.capacity)) * 100
  }
  column {
    header "^S1^"    /* Survivor 1 Space - Percent Used */
    data (1-((sun.gc.generation.0.space.2.capacity - sun.gc.generation.0.space.2.used)/sun.gc.generation.0.space.2.capacity)) * 100
  }
  ......
}

4、jstack 命令

jstack:输入指定过程以后时刻在 JVM 中的线程信息,为了分明的展现其成果,在服务启动时创立线程死锁,而后通过该命令就会把产生死锁的线程打印进去,通过输入能够发现两条相互期待的线程信息;

$ jstack 1281
Found one Java-level deadlock:
=============================
"test-thread-02":
  waiting for ownable synchronizer 0x00000007b00a35d0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "test-thread-01"
"test-thread-01":
  waiting for ownable synchronizer 0x00000007b00a35a0, (a java.util.concurrent.locks.ReentrantLock$NonfairSync),
  which is held by "test-thread-02"

Java stack information for the threads listed above:
===================================================
"test-thread-02":
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007b00a35d0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

"test-thread-01":
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007b00a35a0> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

Found 1 deadlock.

5、jmap 命令

jmap:能够输入指定过程的内存中对象映射信息,或者堆的要害信息、内存的应用统计、GC 算法、配置、类的实例信息及内存占用等,该命令在解决 JVM 问题时也常常应用;

$ jmap 1281

$ jmap -heap 1281
Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 536870912 (512.0MB)
   
Heap Usage:
    PS Young Generation
    Eden Space:
    From Space:
    To Space:
    PS Old Generation

$ jmap -histo:live 1281
 num     #instances         #bytes  class name
----------------------------------------------
1311:             1             32  com.explore.facade.FacadeApp$$EnhancerBySpringCGLIB$$313d9e3

四、可视化工具

1、jconsole

Java 内置的 JVM 性能监控工具,在相熟上述的命令行工具之后,对于该可视化工具的应用不会太生疏,在命令中能够查看到的默认参数或者利用自定义配置,在该工具中也能够找到,并且以图形化的形式出现;

$ jconsole  # 通过该命令会唤起 jconsole 界面

这里抉择线程一栏,能够直观的看到线程数量的变动曲线,也能够在下方查看某个线程的具体信息,并且能够通过检测死锁性能,发现在服务中创立的 test-thread-01 和 test-thread-02 两条线程;

2、visualvm

VisualVM 作为解决 JVM 问题的常用工具,集成的功能丰富且弱小,此处通过 Idea 插件的形式启动 FacadeApp 微服务,在过程主页能够看到自定义的配置,线程一栏因为检测到死锁间接给到异样提醒;

在监督一栏能够通过【堆 dump】查看具体的信息,能够查看类的实例数和大小,并且实现了后果排序和占用统计;此处信息在定位和解决 JVM 问题时十分重要;

对于 JVM 的监控工具来说,其能力与罕用的命令行语法差别很小,并且这些命令在 jdk 中 tools.jar 包也能够找到其对应的类,对于一些更高级的监控平台来说,例如 Kuboard、Skywalking 等,也对这些底层能力做了集成,其原理应该也是大同小异。

五、参考源码

编程文档:https://gitee.com/cicadasmile/butte-java-note

利用仓库:https://gitee.com/cicadasmile/butte-flyer-parent

正文完
 0