JVM及Java监控原理与实践

简介

主要是介绍一下对运行Java程序的一些跟踪,以及对JVM内存等方面进行运维的一些方法。java

反解析class文件的工具使用

  • 通常使用jd-gui工具进行反编译class文件
  • 有些jd-gui没法反编译的class,能够使用luyten工具进行反编译

Java进程分析命令介绍

jps

用于获取全部的JVM进程信息,相似于linux的ps命令linux

//输出进程号与执行的主类名(jar包名)
jps -l 

结果以下:

30352
20708 sun.tools.jps.Jps
6876 mtex-config-0.0.1-SNAPSHOT.jar
复制代码

jstat

用于监控java进程内部各种运行状态信息的工具,能够监控本地或远程虚拟机类装载、内存、垃圾回收等信息。spring

//监控GC状况 间隔1000毫秒执行1次 执行5次
jstat -gc 6876 1000 5

执行结果以下:

C:\Users\dell>jstat -gc 6876 1000 5
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
13824.0 15872.0 13804.6  0.0   140288.0 129170.6  102400.0   19730.9   54528.0 52078.9 7168.0 6684.3     10    0.143   2      0.172    0.315
13824.0 15872.0 13804.6  0.0   140288.0 129170.6  102400.0   19730.9   54528.0 52078.9 7168.0 6684.3     10    0.143   2      0.172    0.315
13824.0 15872.0 13804.6  0.0   140288.0 129170.6  102400.0   19730.9   54528.0 52078.9 7168.0 6684.3     10    0.143   2      0.172    0.315
13824.0 15872.0 13804.6  0.0   140288.0 129170.6  102400.0   19730.9   54528.0 52078.9 7168.0 6684.3     10    0.143   2      0.172    0.315
13824.0 15872.0 13804.6  0.0   140288.0 129170.6  102400.0   19730.9   54528.0 52078.9 7168.0 6684.3     10    0.143   2      0.172    0.315

结果说明:

S0C 年轻代s0区容量
S1C 年轻代s1区容量
S0U 年轻代s0区使用量
S1U 年轻代s1区使用量
EC  年轻代eden区容量
EU	年轻代eden区容量
OC  老年代容量
OU  老年代使用量
MC  元空间容量
MU  元空间使用量
CCSC 压缩类空间容量
CCSU 压缩类空间使用大小
YGC  从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc时间
FGC  从应用程序启动到采样时全gc次数
FGCT 从应用程序启动到采样时全gc时间
GCT  从应用程序启动到采样时gc用的总时间(s)

复制代码

s0和s1中必然有一个的使用空间为0,用于复制交换apache

JDK 1.8如下MC/MU指标为PC/PU。(jdk1.8使用元空间替换了永久代)tomcat

经过参数的不一样,能够进行某些方面的重点信息关注bash

选项 做用
-class 监视类装载、卸载数量、总空间以及类装载所耗费的时间
-gc 监视Java堆情况,包括Eden区、两个survivor区、老年代、元空间的容量、已用空间、GC时间合计等信息
-gccapacity 监视内容与-gc基本相同,但输出主要关注Java堆各个区域使用到的最大、最小空间
-gcutil 监视内容与-gc基本相同,但输出主要关注已使用空间占总空间的百分比
-gccause 与-gcutil功能同样,可是会额外输出致使上一次GC产生的缘由
-gcnew 监视新生代GC情况
-gcnewcapacity 监视内容与-gcnew基本相同,输出主要关注使用到的最大、最小空间
-gcold 监视老年代情况
-gcoldcapacity 监视内容与-gcold基本相同,输出主要关注用到的最大、最小空间
-gcmetacapacity 输出元数据用到的最大、最小空间
-compiler 输出JIT编译器编译过的方法、耗时等信息
-printcompilation 输出已经被JIT编译的方法

jmap

能够用来查询堆中的实例或者进行堆dump等。app

//显示堆中对象统计信息,包括类、实例数、合计占用量

jmap -histo 6876 > a.txt


 num     #instances #bytes class name
----------------------------------------------
   1:        652896       67501960  [B
   2:        493614       47624832  [C
   3:         54335       17164304  [I
   4:        126862        3044688  java.lang.String
   5:         28292        2489696  java.lang.reflect.Method
   6:         27951        1786648  [Ljava.lang.Object;
   7:         21992        1334608  [Lorg.springframework.boot.context.properties.source.ConfigurationPropertyName$ElementType;
   8:         18122        1311816  [Ljava.util.HashMap$Node;
   9:         32653        1306120  java.util.LinkedHashMap$Entry
  10:         10985        1219992  java.lang.Class
  11:         35321        1130272  java.util.concurrent.ConcurrentHashMap$Node
  12:         17251         966056  java.util.LinkedHashMap
  13:         29707         950624  java.util.HashMap$Node
  14:         45305         908512  [Ljava.lang.Class;
  15:           512         724368  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  16:         13340         640320  java.util.HashMap
  17:          7763         604160  [S
  18:          7641         550152  java.lang.reflect.Field
  ...

复制代码

执行此命令须要将输出重定向到文件里,不然会有几千上万行运维

//生成堆快照信息
jmap -dump:format=b,file=heap.hprof 6876

复制代码

堆内存快照信息

jstack

用于生成java的线程快照信息eclipse

jstack -l 6876 > threadDump.txt

执行结果:


2020-03-23 16:51:55
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.65-b01 mixed mode):

"DestroyJavaVM" #58 prio=5 os_prio=0 tid=0x0000000060c4a000 nid=0x6618 waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

   Locked ownable synchronizers:
	- None

"http-nio-8601-Acceptor" #32 daemon prio=5 os_prio=0 tid=0x0000000060c49800 nid=0x824 runnable [0x00000000648de000]
   java.lang.Thread.State: RUNNABLE
	at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:422)
	at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:250)
	- locked <0x00000000e0c3b670> (a java.lang.Object)
	at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:463)
	at org.apache.tomcat.util.net.NioEndpoint.serverSocketAccept(NioEndpoint.java:73)
	at org.apache.tomcat.util.net.Acceptor.run(Acceptor.java:95)
	at java.lang.Thread.run(Thread.java:745)
	
...

复制代码

此命令也最好能够重定向到文件,输出结果较多工具

Java VisualVM工具介绍

VisualVM是目前为止JDK发布功能最强大的运行监控故障处理程序。

工具路径

在jdk路径的bin目录下,jvisualvm.exe

监控本地项目

双击工具,进入主界面,左侧便可看到本地的java进程,双击便可在右侧查看内容。

本地项目

监控远程项目

执行java -jar启动命令时候加入如下参数,hostname为远程的主机名,port使用一个没被占用的端口

-Djava.rmi.server.hostname=xxxxxx -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.managementote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

复制代码

双击左侧远程,添加主机IP,远程下会出现对应的主机,双击选择添加JMX链接,弹框输入端口。点击肯定,便可进行远程监控。

本地项目

总体状况监控

总体状况

线程监控

线程

对象状况监控

对象

Eclipse Memory Analyzer工具安装使用

一、安装

eclipse -->help --> eclipse marketplace,输入memory,搜索出具体的插件,进行安装。

内存分析工具安装

二、使用

使用jmap命令或者经过vusal工具dump下内存快照,拖进eclipse便可。

对象列表

实例排序

可疑报告

经常使用的JVM配置参数

参数名称 含义 默认值
-Xms 初始堆大小 物理内存的1/64
-Xmx 最大堆大小 物理内存的1/4
-XX:NewSize 年轻代的初始大小
-XX:MaxNewSize 年轻代的最大值
-Xmn 年轻代的大小,若是经过-Xmn来配置新生代的内存大小,那么-XX:newSize = -XX:MaxNewSize = -Xmn
-XX:NewRatio 年轻代与老年代的比例 4 表示 年轻代与老年代比例为 1:4
-XX:SurvivorRatio 两个Survivor区与eden的比例 8 表示两个survivor:eden为 2:8

查看本机默认参数命令

java -XX:+PrintFlagsFinal > E:\ab.txt
复制代码

如何查看高CPU占用的线程

示例:

一、找到java的进程

C:\Users\dell>jps -l

24352 cn.mastercom.MtexConfigApplication
30352
43508 sun.tools.jps.Jps
复制代码

二、对具体进程进行线程dump

C:\Users\dell\Desktop>jstack -l 24352 > thread.txt
复制代码

三、使用工具查看占用高的线程ID

linux经过top 命令进程查询

top -H -p 24352

top - 16:44:36 up 74 days,  1:22,  1 user,  load average: 0.52, 0.39, 0.39
Threads:  30 total,   0 running,  30 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.3 us,  0.3 sy,  0.0 ni, 99.0 id,  0.3 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem :  1882752 total,    92228 free,   980456 used,   810068 buff/cache
KiB Swap:        0 total,        0 free,        0 used.   706556 avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                                                                       
17063 root      20   0 2525764 138224  12788 S  0.0  7.3   0:00.00 java                                                                                          
17065 root      20   0 2525764 138224  12788 S  0.0  7.3   0:02.62 java                                                                                          
17067 root      20   0 2525764 138224  12788 S  0.0  7.3   0:05.73 java                                                                                          
17068 root      20   0 2525764 138224  12788 S  0.0  7.3   0:00.00 java                                                                                          
17069 root      20   0 2525764 138224  12788 S  0.0  7.3   0:00.00 java                                                                                          
17070 root      20   0 2525764 138224  12788 S  0.0  7.3   0:00.00 java                                                                                          
17071 root      20   0 2525764 138224  12788 S  0.0  7.3   0:07.06 java                                                                                          
17072 root      20   0 2525764 138224  12788 S  0.0  7.3   0:01.59 java                                                                                          
17073 root      20   0 2525764 138224  12788 S  0.0  7.3   0:00.00 java      

能够看到CPU占用高的百分比
复制代码

windwos能够使用ProcessExplorer软件进行查看

线程分析

四、将线程ID转为16进制,由于线程dump的线程ID是使用16进制的。

43404 --> A98C
复制代码

五、去以前dump的线程映像中查看对应线程

"Catalina-utility-1" #17 prio=1 os_prio=-2 tid=0x000000006130b000 nid=0xa98c waiting on condition [0x000000005e7be000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000e358e9a0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1088)
	at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
	at java.lang.Thread.run(Thread.java:745)

   Locked ownable synchronizers:
	- None
复制代码

若是是本身写的代码,能够从上面查看到具体的问题。

相关文章
相关标签/搜索