JVM的内存分析命令解析

  其他常见问题
内容纲要

概要描述


本案例简单介绍几个JVM内存分析相关的命令,以及案例解析;
本案例环境:TDH 5.2.2 inceptor-server 的内存分析

详细说明


JVM内存模型比较复杂,本文只简单介绍一下堆内存的分析;使用到的命令包括以下:

  • jps
  • jstat
  • jmap
  • jstack
  • jinfo

内存模型

JVM 内存模型主要有三大块:堆内存、方法区和栈。

  • 堆内存是 JVM中 最大的一块,主要是用来为对象实例分配内存;由年轻代和老年代组成,年轻代内存又被分成三部分,Eden空间、From Survivor空间、To Survivor空间,默认情况下年轻代按照8:1:1的比例来分配;
  • 方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆),方法区大小一般比较固定,jstat 时使用率高是正常现象
  • 栈又分为java虚拟机栈和本地方法栈,主要用于方法的执行;

file

jps

jps 作用是显示当前系统的 java 进程情况,及其 id 号

jps [-q] [-mlvV] [hostid]

例如:查看当前系统下,当前用户运行的java进程( -v可以输出当前java进程的启动参数)

# jps
428 InceptorServer2
4003 Jps

# jps -v
428 InceptorServer2 -agentpath:/usr/lib/inceptor/bin/libagent.so -XX:PermSize=512m -XX:MaxPermSize=2g -Djava.net.preferIPv4Stack=true -Dsun.net.inetaddr.ttl=60 -XX:+UseParNewGC -XX:NewRatio=4 -XX:+CMSClassUnloadingEnabled -XX:MinHeapFreeRatio=100 -XX:MaxHeapFreeRatio=100 -XX:CMSMaxAbortablePrecleanTime=1000 -XX:+ExplicitGCInvokesConcurrent -XX:MaxTenuringThreshold=4 -XX:TargetSurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -Xms2048m -Xmx4096m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Djava.library.path=/usr/lib/hadoop/lib/native -Dspark.akka.threads=8 -Dspark.akka.threads=8 -Dspark.rdd.compress=false -Dspark.storage.memoryFraction=0.5 -Dspark.driver.host=tdh-01 -Dclass.default.serializer= -Dspark.fastdisk.dir=/vdir/mnt/ramdisk/ngmr -Dspark.storage.fastdiskFraction=0.5 -Dngmr.task.pipeline=false -Dngmr.task.pipeline.start.fraction=0.5 -Dngmr.task.pipeline.task.timeout.ms=-1 -Dspark.local.dir=/vdir/mnt/disk1/hadoop/ngmr/inceptor1 -Ds
3985 Jps -Dapplication.home=/usr/java/jdk1.7.0_71 -Xms8m

jstat

jstat (JVM statistics Monitoring) 是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集等运行数据。

jstat -option [-t] [-h lines] vmid [interval [count]]

例如:查看vmid为428的进程的GC统计概述,每隔1000ms统计一次,共输出5次( -gc打印的内容更详细,但是可读性不如 -gcutil)

$ jstat -gcutil 428 1000 5
  S0      S1     E      O      P      YGC    YGCT     FGC    FGCT    GCT
  0.00  11.42  69.45  24.25   7.36    489   20.144     2    0.165   20.308
  0.00  11.42  69.46  24.25   7.36    489   20.144     2    0.165   20.308
  0.00  11.42  69.46  24.25   7.36    489   20.144     2    0.165   20.308
  0.00  11.42  69.46  24.25   7.36    489   20.144     2    0.165   20.308
  0.00  11.42  69.46  24.25   7.36    489   20.144     2    0.165   20.308
显示列名 具体描述
S0 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比
S1 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比
E 年轻代中Eden(伊甸园)已使用的占当前容量百分比
O 老年代已使用的占当前容量百分比
P 永久代已使用的占当前容量百分比
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 从应用程序启动到采样时老年代(Fullgc)gc次数
FGCT 从应用程序启动到采样时老年代(Fullgc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)

jmap

jmap 可以生成 java 程序的 dump 文件,也可以查看堆内对象示例的统计信息、查看 ClassLoader 的信息以及 finalizer 队列;
一般在运行缓慢、性能下降时收集;

jmap [option] pid

例如:查看pid为428的进程的堆的活对象统计,包括对象数、内存大小( :live 则只统计这个jmap 触发的 fgc 之后依然保留下来的对象,因此强烈建议带上live

$ sudo -u hive jmap -histo:live 428
 num     #instances         #bytes  class name
----------------------------------------------
   1:       7516794      240537408  java.util.Hashtable$Entry
   2:        726798      236990472  [B
   3:       4998671      159957472  java.util.concurrent.ConcurrentHashMap$HashEntry
   4:       1644249      140301752  [C
   5:         13815       52684464  [Ljava.util.Hashtable$Entry;
   6:        166425       51313208  [S
   7:        131544       45079712  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
   8:         83768       43484088  [I
   9:       1627768       40297248  [Ljava.lang.String;
  10:        259394       37995216  
 ...            ...            ...  ...
9998:             1             16  akka.actor.ActorPathExtractor$
Total      23593415     1375506264

jmap 主要看哪些对象占用了大量的内存空间,占用的是否合理等信息,需要同时关注数量(instances),大小(bytes)
jmap 信息的最后的一行 Total 显示了对象的数量以及他们使用的内存信息;

jstack

jstack 是用于生成 java 虚拟机当前时刻的线程快照。
线程快照是当前 JVM 内每一个线程正在执行的方法堆栈的集合,一般在服务卡住的时候收集(如线程间死锁、死循环、请求外部资源导致的长时间等待等); 线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。

jstack [-l] pid

例如:查看pid为428进程对应的线程快照、各线程的运行情况等信息

# sudo -u hive jstack 428
2019-10-09 19:00:28
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.71-b01 mixed mode):

"ForkJoinPool-2-worker-13" daemon prio=10 tid=0x00007f58c41a1800 nid=0xdb2 waiting on condition [0x00007f585befd000]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006c30838a0> (a scala.concurrent.forkjoin.ForkJoinPool)
        at scala.concurrent.forkjoin.ForkJoinPool.scan(ForkJoinPool.java:2075)
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

"ForkJoinPool-2-worker-15" daemon prio=10 tid=0x00007f5910005800 nid=0xdb1 waiting on condition [0x00007f585acea000]
   java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006c30838a0> (a scala.concurrent.forkjoin.ForkJoinPool)
        at scala.concurrent.forkjoin.ForkJoinPool.idleAwaitWork(ForkJoinPool.java:2135)
        at scala.concurrent.forkjoin.ForkJoinPool.scan(ForkJoinPool.java:2067)
        at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
        at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)

使用jstack命令查看线程堆栈信息时可能会遇到以下几种线程状态,重点关注相同方法的数量和异常状态的方法;

线程状态 具体描述
NEW 未启动的,不会出现在Dump中
RUNNABLE 在虚拟机内执行的
BLOCKED 受阻塞并等待监视器锁
WATING 无限期等待另一个线程执行特定操作
TIMED_WATING 有时限的等待另一个线程的特定操作
TERMINATED 已退出的

jstack 主要看线程之间资源抢占情况,是分析线程执行快慢的一种方法;

jinfo

jinfo(JVM Configuration info) 是实时查看和调整虚拟机运行参数的命令。和 jps -v不同的地方是,jinfo 可以显示未指定的参数的值,也就是默认运行参数的值;

命令格式
jinfo [option] pid

例如:查看pid为428的进程的运行参数(如果不带任何参数,可以显示该进程对应的所有JVM信息)

$ jinfo -flags 428 |more
Attaching to process ID 428, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.71-b01

-agentpath:/usr/lib/inceptor/bin/libagent.so -XX:PermSize=512m -XX:MaxPermSize=2g -Djava.net.preferIPv4Stack=true -Dsun.net.inetaddr.ttl=60 -XX:+UseParNewGC -XX:NewRatio=4 -XX:+CMSClassUnloadingEnabled -XX:MinHeapFreeRatio=100 -XX:MaxHeapFreeRatio=100 -XX:CMSMaxAbortablePrecleanTime=1000 -XX:+ExplicitGCInvokesConcurrent -XX:MaxTenuringThreshold=4 -XX:TargetSurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -Xms2048m -Xmx4096m -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -Djava.library.path=/usr/lib/hadoop/lib/native -Dspark.akka.threads=8 -Dspark.akka.threads=8 -Dspark.rdd.compress=false -Dspark.storage.memoryFraction=0.5 -Dspark.driver.host=tdh-01 -Dclass.default.serializer= -Dspark.fastdisk.dir=/vdir/mnt/ramdisk/ngmr -Dspark.storage.fastdiskFraction=0.5 -Dngmr.task.pipeline=false -Dngmr.task.pipeline.start.fraction=0.5 -Dngmr.task.pipeline.task.timeout.ms=-1 -Dspark.local.dir=/vdir/mnt/disk1/hadoop/ngmr/inceptor1 -Dspark.driver.port=51888 -Dspark.driver.portfixed -Dinceptor.executorID.zkPath=/inceptor1/executorID -Dinceptor.executorID.zkServer=tdh-01,tdh-02,tdh-03 -Dinceptor.executorID.zkPort=2181 -Dinceptor.executorID.zkTimeout=10000 -Dspark.kryoserializer.buffer.mb=4 -Dshark.checkpoint.dir= -Dspark.ui.port=4040 -Dspark.cleaner.ttl=14400 Djava.security.auth.login.config=/etc/inceptor1/conf/kafka_client_jaas.conf -Dhive.log.dir=/var/log/inceptor1 -Dhive.log.file=hive-server2.log

jinfo在不加任何参数的情况下,输出内容比较详细,一般用来分析脏包;也可以用来检查启动参数是否正常;

这篇文章对您有帮助吗?

平均评分 0 / 5. 次数: 0

尚无评价,您可以第一个评哦!

非常抱歉,这篇文章对您没有帮助.

烦请您告诉我们您的建议与意见,以便我们改进,谢谢您。