性能监控
一种以非强行或者入侵方式收集或查看应用运营性能数据的活动。
监控通常是指一种在生产、质量评估或者开发环境下实施的带有预防或主动性的活动。
当应用相关干系人提出性能问题却没有提供足够多的线索时,首先我们需要进行性 能监控,随后是性能分析。
GC频繁
cpu load过高
OOM
内存泄漏
死锁
程序响应时间较长
概述
openjdk中各个命令的源码
https://hg.openjdk.org/jdk/jdk11/file/1ddf9a99e4ad/src/jdk.jcmd/share/classes/sun/tools
jps:查看正在运行的java进程
显示指定系统内所有的HotSpot虚拟机进程(查看虚拟机进程信息),可用于查询正在运行的虚拟机进程。(和linux的ps命令类似)
说明:对于本地虚拟机进程来说,进程的本地虚拟机ID与操作系统的进程ID是一致的,是唯一的。
hhy@hhydeMacBook-Pro ~ % jps 54259 Jps 54227 Main hhy@hhydeMacBook-Pro ~ %jps命令本身也是一个进程,Main是idea程序
它的基本使用语法为:
jps [options] [hostid]
我们还可以通过追加参数,来打印额外的信息。q参数是单独的,hostid可以监听远程java程序
hhy@hhydeMacBook-Pro ~ % jps -help usage: jps [-help] jps [-q] [-mlvV] [<hostid>] Definitions: <hostid>: <hostname>[:<port>]-q:仅仅显示LVMID (local virtual machine id),即本地虚拟机唯一id。不显示主类的名称等
-l:输出应用程序主类的全类名 或如果进程执行的是jar包,则输出jar完整路径
-m:输出虚拟机进程启动时传递给主类main()的参数
-v:列出虚拟机进程启动时的JVM参数。比如:-Xms20m-Xmx50m是启动程序指定的jvm参数。只能查看手动设置的jvm参数,默认的jvm参数值看不到,得用jinfo命令
说明:以上参数可以综合使用。
如果某 Java进程关闭了默认开启的UsePerfData参数(即使用参数-XX:-UsePerfData),那么jps命令(以及下面介绍的jstat)将无法探知该Java 进程。
测试-l参数:
hhy@hhydeMacBook-Pro ~ % jps -l 54227 com.intellij.idea.Main 54316 sun.tools.jps.Jps测试-m参数:
//某个启动类参数太长,将命令执行结果写入到txt文本中 jps -m >a.txt 54450 Jps -m 54227 Main 54437 Launcher /Users/hhy/Applications/IntelliJ IDEA.app/Contents/plugins/java/lib/jps-builders.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/plugins/java/lib/jps-builders-6.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/plugins/java/lib/jps-javac-extension.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/util-8.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/util_rt.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/platform-loader.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/annotations.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/module-intellij.libraries.fastutil.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/module-intellij.libraries.oro.matcher.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/module-intellij.libraries.lz4.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/module-intellij.libraries.aalto.xml.jar:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/module-intellij. 54406 RemoteMavenServer36 54438 Main atguigu测试-v参数:
4488 ScannerTest -javaagent:/Users/hhy/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=57904 -Dfile.encoding=UTF-8
hostid参数
RMI注册表中注册的主机名。 如果想要远程监控主机上的java程序,需要安装jstatd。
对于具有更严格的安全实践的网络场所而言,可能使用一个自定义的策略文件来显示对特定的可信主机或网络的访问,尽管这种技术容易受到IP地址欺诈攻击。
如果安全问题无法使用一个定制的策略文件来处理,那么最安全的操作是不运行jstatd服务器,而是在本地使用jstat和jps工具。
jstat:参看jvm统计信息
jstat(JVM Statistics Monitoring Tool):用于监视虚拟机各种运行状态信息的命令行工具。它可以显示本地或者远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运行期定位虚拟机性能问题的首选工具。常用于检测垃圾回收问题以及内存泄漏问题。
官方文档:
http://docs.oracle.com/javase/8/docs/technotes/tools/unix/jstat.html
基本语法:
Jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]
generalOption: 一般选项, 比如-help
outputOptions: 一个或多个输出选项,由单个
statOption以及任何-t、-h和-J选项组成。
Vmid: 虚拟机标识符,这是一个表示目标JVM的字符串。一般语法如下:
[协议:][//]lvmid[@hostname[:port]/servername]
vmid就是进程pid,可以直接用pid。
Interval:间隔[s|ms], 样间隔以指定单位、秒(s)或毫秒(ms)为单位。默认单位是毫秒。必须是正整数。指定时,
jstat命令会在每个间隔内产生输出。
Count(计数): 要显示的样本数量。默认值为无限,这会导致jstat命令显示统计数据,直到目标JVM终止或jstat命令终止。这个值必须是正整数。
-t: 从程序启动到现在持续了多少s
-h: head, 打印命令输出的前n条。
option有如下参数, 前面带- :
类加载器相关的
class:显示有关类加载器行为的统计数据。类的装载、卸载数量、总空间、类装载所消耗的时间等
垃圾回收相关的
gc:显示垃圾收集堆行为的统计数据。包括Eden区、两个Survivor区、老年代、永久代等的容量、已用空间、Gc时间合计等信息。
gccapacity:显示有关各代人容量及其相应空间的统计数据。但输出主要关注java堆各个区域使用到的最大、最小空间
gccause:显示有关垃圾收集统计数据的摘要(与-gcutil相同),以及上次和当前(如果适用)垃圾收集事件的原因,即额外输出导致最后一次或者当前正在发生的gc产生的原因。
gcutil:显示有关垃圾收集统计数据的摘要。与-gc基本相同,输出主要关注已经使用空间占总空间的百分比
gcnew:显示新生代行为的统计数据。
gcnewcapacity:显示有关新一代及其相应空间大小的统计数据。输出内容主要关注使用到的最大、最小空间
gcold:显示有关旧一代行为和元空间统计数据的统计数据。
gcoldcapacity:显示有关旧一代尺寸的统计数据。
gcmetacapacity:显示有关元空间大小的统计数据。
JIT相关的:
compiler:显示有关Java HotSpot VM Just-in-Time编译器行为的统计数据。
printcompilation:显示Java HotSpot VM编译方法统计信息。
测试- class参数
先查看有哪些java进程和pid
hhy@hhydeMacBook-Pro ~ % jps -l 54227 com.intellij.idea.Main 54406 org.jetbrains.idea.maven.server.RemoteMavenServer36 54487 org.jetbrains.jps.cmdline.Launcher 54488 com.dubbo.ScannerTest 54732 sun.tools.jps.Jps
查看com.dubbo.ScannerTest进程:
hhy@hhydeMacBook-Pro ~ % jstat -class 54488 Loaded Bytes Unloaded Bytes Time 743 1452.0 0 0.0 0.08
Loaded , 已加载类的个数
第一个Bytes, 已加载类占用内存的大小
Unloaded,已卸载类的个数
第二个Bytes, 已卸载类占用内存的大小
Time, 命令花费的时间
测试interval参数
默认单位是毫秒。必须是正整数。jstat命令会在每个间隔内产生输出。
hhy@hhydeMacBook-Pro ~ % jstat -class 54488 1000 Loaded Bytes Unloaded Bytes Time 743 1452.0 0 0.0 0.08
测试count参数
要显示的样本数量。默认值为无限,这会导致jstat命令显示统计数据,直到目标JVM终止或jstat命令终止。这个值必须是正整数。
打印10次结束
hhy@hhydeMacBook-Pro ~ % jstat -class 54488 1000 10 Loaded Bytes Unloaded Bytes Time 743 1452.0 0 0.0 0.08
测试-t参数
输出Timestamp, 程序启动到现在持续了多少秒, 每1000ms打印一次, 10次后结束命令
hhy@hhydeMacBook-Pro ~ % jstat -class -t 54488 1000 10 Timestamp Loaded Bytes Unloaded Bytes Time 2522.0 743 1452.0 0 0.0 0.08 2523.0 743 1452.0 0 0.0 0.08 2524.0 743 1452.0 0 0.0 0.08 2525.0 743 1452.0 0 0.0 0.08 2526.0 743 1452.0 0 0.0 0.08 2527.0 743 1452.0 0 0.0 0.08 2528.0 743 1452.0 0 0.0 0.08 2529.0 743 1452.0 0 0.0 0.08 2530.0 743 1452.0 0 0.0 0.08 2531.0 743 1452.0 0 0.0 0.08
测试-h
打印前3条结果。
hhy@hhydeMacBook-Pro ~ % jstat -class -t -h3 54488 1000 10
测试option参数
-gc
输出结果说明:
S0C: survivor0区容量
S1C:survivor1区容量
S0U: survivor0区已经使用的容量
S1U: survivor1区已经使用的容量
EC: eden区容量
EU:eden区已经使用的容量
OC:old区容量
OU:old区已经使用的容量
MC: metadata元空间容量
MU:metadata元空间已经使用的容量
CCSC:压缩类容量
CCSU:压缩类已经使用的容量
YGC: youg gc次数
YGCT: youg gc花费的时间
FGC: full gc次数
FGCT: full gc花费的时间
GCT: 总的gc时间,youg + full
下面的例子更直观。
启动参数设置堆内存大小为60m。 默认新生代:老年代 = 1:2 = 20m :40m。
新生代中, eden区和survivor区比例为 8:1:1 , 则 eden:s0:s1= 2m:2m:16m
package com.dubbo; import java.util.ArrayList; /** * -Xms60m -Xmx60m -XX:SurvivorRatio=8 */ public class GCTest { public static void main(String[] args) { ArrayList<byte[]> list = new ArrayList<>(); for (int i=0; i<1000; i++) { byte[] arr = new byte[1024 * 100]; //100kb list.add(arr); try { Thread.sleep(120); }catch (InterruptedException e) { e.printStackTrace(); } } } }
-gcutil
显示有关垃圾收集统计数据的摘要。与-gc基本相同,输出主要关注已经使用空间占总空间的百分比
每隔1000ms打印一次,共打印30次结束
jstat -gcutil 55582 1000 30GCT = YGCT + FGCT , gc总时间
-gccause
显示有关垃圾收集统计数据的摘要(与-gcutil相同),以及上次和当前(如果适用)垃圾收集事件的原因,即额外输出导致最后一次或者当前正在发生的gc产生的原因。
Allocation Failure : 新生代eden没有足够空间分配对象
jstat经验
我们可以比较 Java进程的启动时间以及总GC 时间(GCT 列),或者两次测量的间隔时间以及总 GC 时间的增量,来得出 GC时间占运行时间的比例。
如果该比例超过20%,则说明目前堆的压力较大;如果该比例超过 90%,则说明堆里几乎没有可用空间,随时都可能抛出 OOM 异常。
第1步: 在长时间运行的Java程序中,我们可以运行jstat命令连续获取多行性能数据,并取这几行数据中 OU列(即已占用的老年代内存)的最小值。
第2步:
然后,我们每隔一段较长的时间重复一次上述操作,来获得多组 OU 最小值。如果这些值呈上涨趋势,则说明该 Java程序的老年代内存已使用量在不断上涨,这意味着无法回收的对象在不断增加,因此很有可能存在内存泄漏。
jinfo:实时查看和修改jvm配置参数
jinfo(configuration info for java)
查看虚拟机配置参数信息,也可用于调整虚拟机的配置参数。
在很多情况下,Java应用程序不会指定所有的Java虚拟机参数。而此时,开发人员可能不知道某一个具体的Java虚拟机参数的默认值。在这种情况下,可能需要通过查找文档获取某个参数的默认值。这个查找过程可能是非常艰难的。但有了jinfo工具,开发人员可以很方便地找到Java虚拟机参数的当前值。
基本语法:
jinfo [option] pid
option参数可分成两类
查看
-sysprops , 查看可以由System.getProperties()获取得的参数
-flag 查看曾经赋值过的一些参数
-flags 具体参数, 查看某个java进程的具体参数
修改
针对boolean类型, -flag [+|-]name
针对非boolean类型, -flag 具体参数=具体参数值
注意:macOS 的 SIP(System Integrity Protection)或代码签名权限拦截了调试请求, 某些命令不能执行,需要重签名
在任意目录下,执行:
cat > debugger.entitlements <<'EOF' <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.security.cs.debugger</key> <true/> </dict> </plist> EOF查看java的安装路径
hhy@hhydeMacBook-Pro jvmdemo % /usr/libexec/java_home -v 8 /Library/Java/JavaVirtualMachines/jdk1.8.0_501.jdk/Contents/Home
在debugger.entitlements文件所在目录下执行:
codesign --entitlements debugger.entitlements --force --sign - /Library/Java/JavaVirtualMachines/jdk1.8.0_501.jdk/Contents/Home/bin/jinfo
如果出现下面结果,则覆盖成功
/Library/Java/JavaVirtualMachines/jdk1.8.0_501.jdk/Contents/Home/bin/jinfo: replacing existing signature
java8还需要执行下面命令
hhy@hhydeMacBook-Pro jvmdemo % codesign --entitlements debugger.entitlements --force --sign - /Library/Java/JavaVirtualMachines/jdk1.8.0_501.jdk/Contents/Home/lib/sa-jdi.jar
-sysprops
Jinfo -sysprops pid
总结
jinfo不仅可以查看运行时某一个Java虚拟机参数的实际取值,甚至可以在运行时修改部分参数,并使之立即生效。
但是,并非所有参数都支持动态修改。参数只有被标记为manageable的flag可以被实时修改。其实,这个修改能力是极其有限的。
java -XX:+PrintFlagsFinal -version grep manageable扩展命令
jmap:到处内存映像文件&内存使用情况
jmap(JVM Memory Map):作用一方面是获取lump文件(堆转储快照文件,二进制文件),它还可以获取目标Java进程的内存相关信息,包括Java堆各区域的使用情况、堆中对象的统计信息、类加载信息等。
开发人员可以在控制台中输入命令“jmap -help”查阅jmap工具的具体使用方式和一些标准选项配置。
官方文档:
jmap
基本语法
jmap [option] <pid>
jmap [option] <executable <core>
jmap [option] [server_id@]<remote server IP or hostname>
其中option包括:
-dump
生成java堆转储快照:dump文件
特别的,dump:live只保存堆中的存活对象
手动的方式:
-jmap -dump:format=b,file=<filename.hprof><pid>
-jmap -dump:live,format=b,file=<filename.hprof><pid> 生产环境通常用live
自动的方式:
-XX:+HeapDumpOnOutOfMemoryError:在程序发生0OM时,导出应用程序的当前堆快照。
-XX:+HeapDumpPath=<filename.hprof> :可以指定堆快照的保存位置。
当程序发生0OM退出系统时,一些瞬时信息都随着程序的终止而消失,而重现0OM问题往往比较困难或者耗时。此时若能在0OM时,自动导出dump文件就显得非常迫切。
一般来说,使用jmap指令生成dump文件的操作算得上是最常用的jmap命令之一,将堆中所有存活对象导出至一个文件之中。
Heap Dump又叫做堆存储文件,指一个Java进程在某个时间点的内存快照。Heap Dump在触发内存快照的时候会保存此刻的信息如下:
说明:
1.通常在写Heap Dump文件前会触发一次FullGC,(自动的方式)所以heap dump文件里保存的都是FullGC后留下的对象信息。
2.由于生成dump文件比较耗时,因此大家需要耐心等待,尤其是大内存镜像生成dump文件则需要耗费更长的时间来完成。
测试手动方式:
hhy@hhydeMacBook-Pro ~ % jmap -dump:format=b,file=1.hprof 58893 Dumping heap to /Users/hhy/1.hprof ... Heap dump file created hhy@hhydeMacBook-Pro ~ % jmap -dump:live,format=b,file=1.hprof 58893 Dumping heap to /Users/hhy/1.hprof ... Heap dump file created
-heap
输出整个堆空间的详细信息,包括GC的使用、堆配置信息,以及内存的使用信息等。
jmap -heap pid
该命令只会显示当前时间点的堆内存情况,比不上jps命令
-histo
输出堆中对象的统计信息,包括类、实例数量和合计容量
特别的:-histo:live只统计堆中的存活对象
jmap -histo pid
小结
由于jmap将访问堆中的所有对象,为了保证在此过程中不被应用线程干扰,jmap需要借助安全点机制,让所有线程停留在不改变堆中数据的状态。也就是说,由jmap导出的堆快照必定是安全点位置的。这可能导致基于该堆快照的分析结果存在偏差。
举个例子,假设在编译生成的机器码中,某些对象的生命周期在两个安全点之间,那么:live选项将无法探知到这些对象。
另外,如果某个线程长时间无法跑到安全点,jmap将一直等下去。
与前面讲的jstat则不同,垃圾回收器会主动将jstat所需要的摘要数据保存至固定位置之中,而jstat只需直接读取即可。
jhat:jdk自带堆分析工具
Sun JDK提供的jhat命令与jmap命令搭配使用,用于分析jmap生成的heap dump文件(堆转储快照)。jhat内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,用户可以在浏览器中查看分析结果(分析虚拟机转储快照信息)。
使用了jhat命令,就启动了一个http服务,端口是7000,即http://1ocalhost:7000/,就可以在浏览器里分析。
说明:jhat命令在JDK9、JDK10中已经被删除,官方建议用VisualVM代替。
jstack:查看堆中线程快照
jstack(JVM StackTrace):用于生成虚拟机指定进程当前时刻的线程快照(虚拟机堆栈跟踪)。线程快照就是当前虚拟机内指定进程的每一条线程正在执行的方法堆栈的集合。
生成线程快照的作用:可用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。这些都是导致线程长时间停顿的常见原因。当线程出现停顿时,就可以用jstack显示各个线程调用的堆栈情况。
官方文档:jstack
在thread dump中,要留意下面几种状态
死锁,Deadlock(重点关注)
等待资源,Waiting(重点关注)conditionon
等待获取监视器,Waiting on monitor entry(重点关注)
阻塞,Blocked(重点关注)
执行中,Runnale
暂停,Suspended
对象等待中,Object.wait()或TIMED_WAITING
停止,Parked
基本语法
它的基本使用语法为:
jstack <option> pid
jstack管理远程进程的话,需要在远程程序的启动参数中增加: -Djava.rmi.server.hostname=.... -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=8888 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false
测试
package com.dubbo; public class ThreadDeadLock { public static void main(String[] args) { StringBuilder s1 = new StringBuilder(); StringBuilder s2 = new StringBuilder(); new Thread(){ @Override public void run() { synchronized (s1) { s1.append("a"); s2.append("1"); try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } synchronized (s2) { s1.append("b"); s2.append("2"); try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } } } } }.start(); new Thread(){ @Override public void run() { synchronized (s2) { s1.append("c"); s2.append("3"); try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } synchronized (s1) { s1.append("d"); s2.append("4"); try { Thread.sleep(100); }catch (InterruptedException e) { e.printStackTrace(); } } } } }.start(); } }
执行jstack命令
hhy@hhydeMacBook-Pro ~ % jps 54227 Main 54406 RemoteMavenServer36 59384 Launcher 59385 ThreadDeadLock 59387 Jps hhy@hhydeMacBook-Pro ~ % jstack 59385
查看输出结果:
最后提示存在deadlock风险
"Thread-1" #20 prio=5 os_prio=31 tid=0x00007f8b86843800 nid=0xa213 waiting for monitor entry [0x000000030afc9000] java.lang.Thread.State: BLOCKED (on object monitor) at com.dubbo.ThreadDeadLock$2.run(ThreadDeadLock.java:47) - waiting to lock <0x000000066ac60278> (a java.lang.StringBuilder) - locked <0x000000066ac602c0> (a java.lang.StringBuilder) "Thread-0" #19 prio=5 os_prio=31 tid=0x00007f8b86843000 nid=0x8303 waiting for monitor entry [0x000000030aec6000] java.lang.Thread.State: BLOCKED (on object monitor) at com.dubbo.ThreadDeadLock$1.run(ThreadDeadLock.java:21) - waiting to lock <0x000000066ac602c0> (a java.lang.StringBuilder) - locked <0x000000066ac60278> (a java.lang.StringBuilder) Found one Java-level deadlock: ============================= "Thread-1": waiting to lock monitor 0x00007f8b878578b8 (object 0x000000066ac60278, a java.lang.StringBuilder), which is held by "Thread-0" "Thread-0": waiting to lock monitor 0x00007f8b770b1808 (object 0x000000066ac602c0, a java.lang.StringBuilder), which is held by "Thread-1" Java stack information for the threads listed above: =================================================== "Thread-1": at com.dubbo.ThreadDeadLock$2.run(ThreadDeadLock.java:47) - waiting to lock <0x000000066ac60278> (a java.lang.StringBuilder) - locked <0x000000066ac602c0> (a java.lang.StringBuilder) "Thread-0": at com.dubbo.ThreadDeadLock$1.run(ThreadDeadLock.java:21) - waiting to lock <0x000000066ac602c0> (a java.lang.StringBuilder) - locked <0x000000066ac60278> (a java.lang.StringBuilder) Found 1 deadlock.
补充:使用代码获取线程信息
package com.dubbo; import java.util.Map; /** * 获取所有线程的堆栈信息 */ public class AllStackTrace { public static void main(String[] args) { Map<Thread, StackTraceElement[]> all = Thread.getAllStackTraces(); for (Map.Entry<Thread, StackTraceElement[]> threadEntry : all.entrySet()) { Thread key = threadEntry.getKey(); StackTraceElement[] value = threadEntry.getValue(); System.out.println("【Thread name is :】" + key.getName()); for (StackTraceElement s : value) { System.out.println("\t" + s.toString()); } } } }
jcmd:多功能命令行
在JDK1.7以后,新增了一个命令行工具jcmd。 它是一个多功能的工具,可以用来实现前面除了jstat之外所有命令的功能。比如:用它来导出堆、内存使用、查看Java进程、导出线程信息、执行Gc、JVM运行时间等。
jcmd拥有jnma·的大部分功能,并且在oracle的官方网站上也推荐使用jcmd命令代jmap命令
官方文档:
jcmd
基本语法
jcmd -l : 列出所有的jvm进程,类似jps -l
jcmd pid help ,针对指定进程,列出支持的所有命令
jcmd pid 具体命令, 显示指定进程的指令命令的数据
你可以探索jcmd中的下述功能,看看有没有适合你项目的监控项:
JFR.stop JFR.start JFR.dump JFR.check VM.native_memory VM.check_commercial_features VM.unlock_commercial_features ManagementAgent.stop ManagementAgent.start_local ManagementAgent.start VM.classloader_stats GC.rotate_log Thread.print JVMTI.data_dump VM.class_hierarchy GC.class_stats GC.class_histogram GC.heap_dump GC.finalizer_info GC.heap_info GC.run_finalization GC.run VM.info VM.uptime VM.dynlibs VM.set_flag VM.flags VM.system_properties VM.command_line VM.version help
测试option选项
查看类的直方图, 类似jmap -histo
jcmd 59385 GC.class_histogram
查看jvm参数, 类似jinfo -sysprops
jcmd 59385 VM.system_properties
GUI工具
使用上一章命令行工具或组合能帮您获取目标Java应用性能相关的基础信息,但它们存在下列局限:
1.无法获取方法级别的分析数据,如方法间的调用关系、各方法的调用次数和调用时间 等(这对定位应用性能瓶颈至关重要)。
2.要求用户登录到目标 Java应用所在的宿主机上,使用起来不是很方便。
3.分析数据通过终端输出,结果展示不够直观。
为此,JDK提供了一些内存泄漏的分析工具,如jconsole,jvisualvm等,用于辅助开发人员定位问题,但是这些工具很多时候并不足以满足快速定位的需求。所以这里我们介绍的工具相对多一些、丰富一些。
Visual Vm
在Visual Vm中安装 gc插件
性能分析
一种以侵入方式收集运行性能数据的活动,它会影响应用的吞吐量或响应性。
性能分析是针对性能问题的答复结果,关注的范围通常比性能监控更加集中。
性能分析很少在生产环境下进行,通常是在质量评估、系统测试或者开发环境下进 行,是性能监控之后的步骤。
打开gc文件
灵活运用命令行工具
dump出队文件
使用阿里的Arthas,或jconsole
jstack查看堆栈信息
性能调优
种为改善应用响应性或吞吐量而更改参数、源代码、属性配置的活动,性能调优 是在性能监控、性能分析之后的活动。