本文来说下JVM线上监控工具


文章目录

  • 概述
  • JVM常见监控工具
  • jps进程监控工具
  • jinfo配置信息查看工具
  • jmap堆内存统计工具
  • heap
  • histo
  • dump
  • 本文参考
  • 本文小结



概述

通过上一篇的JVM垃圾回收知识,我们了解了JVM具体的 垃圾回收算法 和几种 垃圾回收器。理论是指导实践的工具,有了理论指导,定位问题的时候,知识和经验是关键基础,数据可以为我们提供依据。

jvisualvm监控gc 线上jvm监控_java


在线上我们经常会遇见如下几个问题

  • 内存泄露;
  • 某个进程突然 CPU 飙升;
  • 线程死锁;
  • 响应变慢。

如果遇到了以上这种问题,在 线下环境 可以有各种 可视化的本地工具 支持查看。但是一旦到 线上环境,就没有这么多的 本地调试工具 支持,我们该如何基于 监控工具 来进行定位问题?

我们一般会基于 数据收集 来定位问题,而数据的收集离不开 监控工具 的处理,比如:运行日志、异常堆栈、GC 日志、线程快照、堆内存快照 等。为了解决以上问题,我们常用的 JVM 性能调优监控工具 大致有:jps、jstat、jstack、jmap、jhat、hprof、jinfo。


JVM常见监控工具

如果想要查看 Java 进程中 线程堆栈 的信息,可以选择 jstack 命令。如果要查看 堆内存,可以使用 jmap 导出并使用 jhat 来进行分析,包括查看 类的加载信息,GC 算法,对象 的使用情况等。可以使用 jstat 来对 JVM 进行 统计监测,包括查看各个 区内存 和 GC 的情况,还可以使用 hprof 查看 CPU 使用率,统计 堆内存 使用情况。下面会详细的介绍这几个工具的用法


jps进程监控工具

jps 是用于查看有权访问的 hotspot 虚拟机 的进程。当未指定 hostid 时,默认查看 本机 jvm 进程,否则查看指定的 hostid 机器上的 jvm 进程,此时 hostid 所指机器必须开启 jstatd 服务。

jps 可以列出 jvm 进程 lvmid,主类类名,main 函数参数, jvm 参数,jar 名称等信息。

命令格式如下

usage: jps [-help]
       jps [-q] [-mlvV] [<hostid>]

Definitions:
    <hostid>:      <hostname>[:<port>]

参数含义如下

  • -q: 不输出 类名称、Jar 名称 和传入 main 方法的 参数;
  • -l: 输出 main 类或 Jar 的 全限定名称;
  • -m: 输出传入 main 方法的 参数;
  • -v: 输出传入 JVM 的参数。

jinfo配置信息查看工具

jinfo(JVM Configuration info)这个命令作用是实时查看和调整 虚拟机运行参数。之前的 jps -v 命令只能查看到显示 指定的参数,如果想要查看 未显示 的参数的值就要使用 jinfo 命令。

Usage:
    jinfo [option] <pid>
        (to connect to running process)
    jinfo [option] <executable <core>
        (to connect to a core file)
    jinfo [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

参数含义如下

  • pid:本地 jvm 服务的进程 ID;
  • executable core:打印 堆栈跟踪 的核心文件;
  • remote server IP/hostname:远程 debug 服务的 主机名 或 IP 地址;
  • server id:远程 debug 服务的 进程 ID。

参数选项说明如下

参数

参数含义

flag

输出指定 args 参数的值

flags

不需要 args 参数,输出所有 JVM 参数的值

sysprops

输出系统属性,等同于 System.getProperties()

查看正在运行的 jvm 进程的 扩展参数。

$ jinfo -flags 31983 
Attaching to process ID 31983, please wait… 
Debugger attached successfully. 
Server compiler detected. 
JVM version is 25.91-b14 
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=20971520 -XX:MaxHeapFreeRatio=90
 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=2097152 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=2097152 -XX:OldSize=18874368 
-XX:+PrintGC -XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops
 -XX:+UseFastUnorderedTimeStamps -XX:+UseParallelGC 
Command line: -Xmx20m -Xms20m -Xmn2m -javaagent:/opt/idea-IU-181.4668.68/lib/idea_rt.jar=34989:/opt/idea-IU-181.4668.68/
bin -Dfile.encoding=UTF-8

查看正在运行的 jvm 进程的所有 参数信息

$ jinfo 31983
Attaching to process ID 31983, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.91-b14
Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment
java.vm.version = 25.91-b14
sun.boot.library.path = /opt/jdk1.8.0_91/jre/lib/amd64
java.vendor.url = http://java.oracle.com/
java.vm.vendor = Oracle Corporation
path.separator = :
file.encoding.pkg = sun.io
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
sun.os.patch.level = unknown
sun.java.launcher = SUN_STANDARD
user.country = CN
user.dir = /home/linchen/projects
java.vm.specification.name = Java Virtual Machine Specification
java.runtime.version = 1.8.0_91-b14
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
os.arch = amd64
java.endorsed.dirs = /opt/jdk1.8.0_91/jre/lib/endorsed
java.io.tmpdir = /tmp
line.separator = 

java.vm.specification.vendor = Oracle Corporation
os.name = Linux
sun.jnu.encoding = UTF-8
java.library.path = /usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib
java.specification.name = Java Platform API Specification
java.class.version = 52.0
sun.management.compiler = HotSpot 64-Bit Tiered Compilers
os.version = 4.15.0-24-generic
user.home = /home/linchen
user.timezone = 
java.awt.printerjob = sun.print.PSPrinterJob
file.encoding = UTF-8
java.specification.version = 1.8
user.name = linchen
java.class.path = /opt/jdk1.8.0_91/jre/lib/charsets.jar:/opt/jdk1.8.0_91/jre/lib/deploy.jar:/opt/jdk1.8.0_91/jre/lib/ext/cldrdata.jar:
/opt/jdk1.8.0_91/jre/lib/ext/dnsns.jar:/opt/jdk1.8.0_91/jre/lib/ext/jaccess.jar:/opt/jdk1.8.0_91/jre/lib/ext/jfxrt.jar:
/opt/jdk1.8.0_91/jre/lib/ext/localedata.jar:/opt/jdk1.8.0_91/jre/lib/ext/nashorn.jar:/opt/jdk1.8.0_91/jre/lib/ext/sunec.jar:
/opt/jdk1.8.0_91/jre/lib/ext/sunjce_provider.jar:/opt/jdk1.8.0_91/jre/lib/ext/sunpkcs11.jar:/opt/jdk1.8.0_91/jre/lib/ext
/zipfs.jar:/opt/jdk1.8.0_91/jre/lib/javaws.jar:/opt/jdk1.8.0_91/jre/lib/jce.jar:/opt/jdk1.8.0_91/jre/lib/jfr.jar:
/opt/jdk1.8.0_91/jre/lib/jfxswt.jar:/opt/jdk1.8.0_91/jre/lib/jsse.jar:/opt/jdk1.8.0_91/jre/lib/management-agent.jar:/opt/jdk1.8.0_91/jre/lib/plugin.jar:/opt/jdk1.8.0_91/jre/lib/resources.jar:/opt/jdk1.8.0_91/jre/lib/rt.jar:/home/linchen/IdeaProjects/core_java/target/classes:/home/linchen/.m2/repository/io/netty/netty-all/4.1.7.Final/netty-all-4.1.7.Final.jar:/home/linchen/.m2/repository/junit/junit/4.12/junit-4.12.jar:/home/linchen/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar:/home/linchen/.m2/repository/com/lmax/disruptor/3.3.0/disruptor-3.3.0.jar:/home/linchen/.m2/repository/com/rabbitmq/amqp-client/5.3.0/amqp-client-5.3.0.jar:/home/linchen/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/opt/idea-IU-181.4668.68/lib/idea_rt.jar
java.vm.specification.version = 1.8
sun.arch.data.model = 64
sun.java.command = com.own.learn.jvm.JinfoTest
java.home = /opt/jdk1.8.0_91/jre
user.language = zh
java.specification.vendor = Oracle Corporation
awt.toolkit = sun.awt.X11.XToolkit
java.vm.info = mixed mode
java.version = 1.8.0_91
java.ext.dirs = /opt/jdk1.8.0_91/jre/lib/ext:/usr/java/packages/lib/ext
sun.boot.class.path = /opt/jdk1.8.0_91/jre/lib/resources.jar:/opt/jdk1.8.0_91/jre/lib/rt.jar:/opt/jdk1.8.0_91/jre/lib/sunrsasign.jar:
/opt/jdk1.8.0_91/jre/lib/jsse.jar:/opt/jdk1.8.0_91/jre/lib/jce.jar:/opt/jdk1.8.0_91/jre/lib/charsets.jar:
/opt/jdk1.8.0_91/jre/lib/jfr.jar:/opt/jdk1.8.0_91/jre/classes
java.vendor = Oracle Corporation
file.separator = /
java.vendor.url.bug = http://bugreport.sun.com/bugreport/
sun.io.unicode.encoding = UnicodeLittle
sun.cpu.endian = little
sun.desktop = gnome
sun.cpu.isalist = 

VM Flags:
Non-default VM flags: -XX:CICompilerCount=3 -XX:InitialHeapSize=20971520 -XX:MaxHeapFreeRatio=90 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=2097152 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=2097152 -XX:OldSize=18874368 -XX:+PrintGC 
-XX:+PrintGCDetails -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps 
-XX:+UseParallelGC 
Command line:  -Xmx20m -Xms20m -Xmn2m -javaagent:/opt/idea-IU-181.4668.68/lib/idea_rt.jar=34989:
/opt/idea-IU-181.4668.68/bin -Dfile.encoding=UTF-8

查看正在运行的 jvm 进程的 环境变量信息。

$ jinfo -sysprops 31983 
Attaching to process ID 31983, please wait… 
Debugger attached successfully. 
Server compiler detected. 
JVM version is 25.91-b14 
java.runtime.name = Java(TM) SE Runtime Environment 
java.vm.version = 25.91-b14 
sun.boot.library.path = /opt/jdk1.8.0_91/jre/lib/amd64 
java.vendor.url = http://java.oracle.com/ 
java.vm.vendor = Oracle Corporation 
path.separator = : 
file.encoding.pkg = sun.io 
java.vm.name = Java HotSpot(TM) 64-Bit Server VM 
sun.os.patch.level = unknown 
sun.java.launcher = SUN_STANDARD 
user.country = CN 
user.dir = /home/linchen/projects 
java.vm.specification.name = Java Virtual Machine Specification 
java.runtime.version = 1.8.0_91-b14 
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment 
os.arch = amd64 
java.endorsed.dirs = /opt/jdk1.8.0_91/jre/lib/endorsed 
java.io.tmpdir = /tmp 
line.separator =

jmap堆内存统计工具

jmap (JVM Memory Map) 命令用来查看 堆内存 使用状况,一般结合 jhat 使用,用于生成 heap dump 文件。jmap 不仅能生成 dump 文件,还可以查询 finalize 执行队列、Java 堆 和 元空间 metaspace 的详细信息,如当前 使用率、当前使用的是哪种 收集器 等等。

如果不使用这个命令,还可以使用 -XX:+HeapDumpOnOutOfMemoryError 参数来让虚拟机出现 OOM 的时候,自动生成 dump 文件。

命令格式如下:

Usage:
    jmap [option] <pid>
        (to connect to running process)
    jmap [option] <executable <core>
        (to connect to a core file)
    jmap [option] [server_id@]<remote server IP or hostname>
        (to connect to remote debug server)

参数含义如下

  • pid:本地 jvm 服务的进程 ID;
  • executable core:打印 堆栈跟踪 的核心文件;
  • remote server IP/hostname:远程 debug 服务的 主机名 或 IP 地址;
  • server id:远程 debug 服务的 进程 ID。

参数选项说明如下:

参数

参数含义

heap

显示堆中的摘要信息

histo

显示堆中对象的统计信息

histo[:live]

只显示 堆 中 存活对象 的统计信息

clstats

显示 类加载 的统计信息

finalizerinfo

显示在 F-Queue 队列 等待 Finalizer 线程执行 finalizer 方法的对象

dump

导出内存转储快照

注意:dump 内存快照分析基本上包含了 histo、clstats、finalizerinfo 等功能。


heap

显示 堆 中的摘要信息。包括 堆内存 的使用情况,正在使用的 GC 算法、堆配置参数 和 各代中堆内存 使用情况。可以用此来判断内存目前的 使用情况 以及 垃圾回收 情况

$ jmap -heap 11368
Attaching to process ID 11368, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.101-b13

using thread-local object allocation.
Parallel GC with 2 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2684354560 (2560.0MB)
   NewSize                  = 1073741824 (1024.0MB)
   MaxNewSize               = 1073741824 (1024.0MB)
   OldSize                  = 1610612736 (1536.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 852492288 (813.0MB)
   used     = 420427144 (400.95056915283203MB)
   free     = 432065144 (412.04943084716797MB)
   49.31741317993014% used
From Space:
   capacity = 113770496 (108.5MB)
   used     = 2299712 (2.19317626953125MB)
   free     = 111470784 (106.30682373046875MB)
   2.021360617079493% used
To Space:
   capacity = 107479040 (102.5MB)
   used     = 0 (0.0MB)
   free     = 107479040 (102.5MB)
   0.0% used
PS Old Generation
   capacity = 1610612736 (1536.0MB)
   used     = 50883368 (48.526161193847656MB)
   free     = 1559729368 (1487.4738388061523MB)
   3.1592552860577903% used

27595 interned Strings occupying 3138384 bytes.

这里主要对 heap configuration 的参数列表说明一下

参数

对应启动参数

参数含义

MinHeapFreeRatio

-XX:MinHeapFreeRatio

JVM堆最小空闲比率(default 40)

MaxHeapFreeRatio

-XX:MaxHeapFreeRatio

JVM堆最大空闲比率(default 70)

MaxHeapSize

XX:Xmx

JVM堆的最大大小

NewSize

-XX:NewSize

JVM堆新生代的默认(初始化)大小

MaxNewSize

-XX:MaxNewSize

JVM堆新生代的最大大小

OldSize

-XX:OldSize

JVM堆老年代的默认(初始化)大小

NewRatio

-XX:NewRatio

JVM堆新生代和老年代的大小比例

SurvivorRatio

-XX:SurvivorRatio

JVM堆年轻代中Eden区与Survivor区的大小比值

MetaspaceSize

-XX:MetaspaceSize

JVM元空间(metaspace)初始化大小

MaxMetaspaceSize

-XX:MaxMetaspaceSize

JVM元空间(metaspace)最大大小

CompressedClass SpaceSize

-XX:CompressedClass SpaceSize

JVM类指针压缩空间大小, 默认为1G

G1HeapRegionSize

-XX:G1HeapRegionSize

使用G1垃圾回收器时单个Region的大小,取值为1M至32M


histo

打印堆的 对象统计,包括 对象实例数、内存大小 等等。因为在 histo:live 前会进行 full gc,如果带上 live 则只统计 活对象。不加 live 的堆大小要大于加 live 堆的大小。

$ jmap -histo:live 12498
 num     #instances         #bytes  class name
----------------------------------------------
   1:         50358        7890344  [C
   2:         22887        2014056  java.lang.reflect.Method
   3:          3151        1485512  [B
   4:         49267        1182408  java.lang.String
   5:          7836         871384  java.lang.Class
   6:         24149         772768  java.util.concurrent.ConcurrentHashMap$Node
   7:         20785         482256  [Ljava.lang.Class;
   8:          8357         435248  [Ljava.lang.Object;
   9:         10035         401400  java.util.LinkedHashMap$Entry
  10:          4803         369488  [Ljava.util.HashMap$Node;
  11:         10763         344416  java.util.HashMap$Node
  12:          5205         291480  java.util.LinkedHashMap
  13:          3055         219960  java.lang.reflect.Field
  14:           120         193408  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  15:         11224         179584  java.lang.Object
  16:          1988         146152  [Ljava.lang.reflect.Method;
  17:          3036         145728  org.aspectj.weaver.reflect.ShadowMatchImpl
  18:          1771         141680  java.lang.reflect.Constructor
  19:          4903         117672  org.springframework.core.MethodClassKey
  20:          3263         104416  java.lang.ref.WeakReference
  21:          2507         100280  java.lang.ref.SoftReference
  22:          2523          97600  [I
  23:          3036          97152  org.aspectj.weaver.patterns.ExposedState
  24:          2072          95280  [Ljava.lang.String;
  25:           954          91584  org.springframework.beans.GenericTypeAwarePropertyDescriptor
  26:          1633          91448  java.lang.Class$ReflectionData
  27:          3142          90520  [Z
  28:          1671          80208  java.util.HashMap
  29:          3244          77856  java.util.ArrayList
  30:          3037          72880  [Lorg.aspectj.weaver.ast.Var;
  31:          1809          72360  java.util.WeakHashMap$Entry
  32:          1967          62944  java.util.LinkedList

其中,class name 是 对象类型,对象 缩写类型 与 真实类型 的对应说明如下

对象缩写类型

对象真实类型

B

byte

C

char

D

double

F

float

I

int

J

long

Z

boolean

[

数组,如[I表示int[]

[L+类名

其他对象


dump

dump 用于导出内存转储快照。常用的方式是通过 jmap 把进程 内存使用情况 dump 到文件中,再用 jhat 分析查看。jmap 进行 dump 的命令格式如下:

jmap -dump:format=b,file=dumpFileName

参数含义如下

参数

参数含义

dump

堆到文件

format

指定输出格式

live

指明是活着的对象

file

指定文件名

通过 jmap 导出 内存快照,文件命名为 dump.dat

jmap -dump:format=b,file=dump.dat 12498
Dumping heap to /Users/XXX/dump.dat ...
Heap dump file created

导出的 dump 文件可以通过 MAT、VisualVM 和 jhat 等工具查看分析,后面会详细介绍。


本文参考

  • 周志明,深入理解Java虚拟机:
  • JVM高级特性与最佳实践,机械工业出版社

本文小结

本文介绍了几种常见的线上JVM监控工具。