JVM性能调优监控工具jps、jstac

与您的主题素材不等,笔者感觉软件工程第一是用来减轻难题的。有个别博客以为“各样孩子都应该学习编制程序”,“你以为学数学只是游戏而已?假若你有看过小编的HTML5调节和测量检验器的话,你会发觉自个儿是叁个程序员,但自己做的办事远不仅仅数学那几个”。
上面两者都允许二个意见,软件工程不只是用微微机语言写的片段片言一字。软件撤消的标题讲明了技师的市场股票总值。

JVM质量调优监察和控制工具jps、jstack、jmap、jhat、jstat、hprof使用详整实例深入分析

鸡犬不留难点的最终进行来自科学、深化清晰的头脑和我们一块以来使用的工具。

第一部分:工具介绍一些:

澳门新葡萄京官网首页 1

具体公司级Java开辟中,有的时候候我们会境遇上边那一个难题:

您有未有介意过这一个 JDK 安装附带的工具?既然那一个大牌同意把那几个工具加到
JDK 里,应该是卓有功效的。

OutOfMemoryError,内部存款和储蓄器不足

为此,在此篇小说里,作者挑了几个 Hotspot
规范设置后可用的小工具来介绍。我们决定忽视那个安全有关的和各类远程方法调用(RMI)、applets、web-start、web-services
工具。让大家把关键放在这里多少个平日开垦者开垦日常选择进度中或许立见成效的工具。注意,要是你只是对命令行工具感兴趣,而不唯有是Java相关的工具,这里介绍了
5 个极其实用的命令行工具。

内部存款和储蓄器走漏

双重故伎重演,下边纵然不是 JDK
工具完整列表,不过大家想给你多少个精粹版本。上边是您用这么些命令能够完毕的确实实用的事体。

线程死锁

0、javap

您能够给 javap(Java
Class文本反编译器)传递那几个使得的参数:

  • -I – 打字与印刷行数和局地变量
  • -p – 打字与印刷富含非public在内的全体类和分子消息,
  • -c – 打字与印刷格局字节码

诸如在名牌的“你实在懂 Classloader 吗?”演讲里,当出现NoSuchMethodException
错误时,大家得以实施以下命令来考察那个类毕竟有啥样成员方法和得到那个类具有想找的新闻:

javap -l -c -p Util2

澳门新葡萄京官网首页 2

澳门新葡萄京官网首页,当调节和测验类内部音信照旧切磋随机字节码顺序时,javap 特别管用。

锁争用(Lock Contention)

1、jjs

澳门新葡萄京官网首页 3

jjs命令能够运行三个 JavaScript
命令终端,你能够把它看做计算器也许用随机的JS字符串测验JS的奇特用法。不要让另叁个JavaScript 谜题让您来不比!

哈哈,看见刚刚爆发了什么了么?不过 JavaScript
是另三个话题,只供给通晓纵然未有 node.js
或浏览器你也足以用jjs知道JS是怎么工作的。

Java进度消耗CPU过高

2、jhat

Java堆深入分析工具(jhat)正如它名字描述的那么:解析dump堆音讯。在底下的小例子里,大家组织了一个OutOfMemoryError ,然后给那几个 java 进度内定-XX:+HeapDumpOnOutOfMemoryError ,这样运维时就能够发生一个 dump
文件供大家剖判。

public class OhMyMemory {

 private static Map map = new HashMap<>();

 public static void main(String[] args) {
   Runtime.getRuntime().addShutdownHook(
     new Thread() {
       @Override
       public void run() {
         System.out.println("We have accumulated " + map.size() + " entries");
       }
     }
   );
   for(int i = 0; ;i++) {
     map.put(Integer.toBinaryString(i), i);
   }
 }
}

发生几个 OutOfMemoryError
很简短(当先二分一气象下我们神不知鬼不觉为之),大家假设不断地创设不让垃圾回收器起成效就足以了。

运维这段代码会发出如下输出:

org.shelajev.throwaway.jdktools.OhMyMemory
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid5644.hprof ...
Heap dump file created [73169721 bytes in 0.645 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.resize(HashMap.java:703)
at java.util.HashMap.putVal(HashMap.java:662)
at java.util.HashMap.put(HashMap.java:611)
at org.shelajev.throwaway.jdktools.OhMyMemory.main(OhMyMemory.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
We have accumulated 393217 entries

是的,大家后天有三个可供解析的文书了。大家对那几个文件进行jhat开首开展深入深入分析,jhat
会深入分析那么些文件开启二个 http 服务器供大家查阅结果。

$ jhat java_pid5644.hprof
Reading from java_pid5644.hprof...
Dump file created Thu Aug 14 14:48:19 EEST 2014
Snapshot read, resolving...
Resolving 1581103 objects...
Chasing references, expect 316 dots...
Eliminating duplicate references........
Snapshot resolved.
Started HTTP server on port 7000
Server is ready.

能够因而拜谒 来查看 dump 的数据。

澳门新葡萄京官网首页 4

在老大页面大家可以透过堆新闻的柱状图领悟毕竟是怎么样耗尽了内存。

澳门新葡萄京官网首页 5

近年来大家得以清晰地看出全体 393567 结点的 HashMap
正是引致程序崩溃的罪魁祸首。固然有更加多能够检查内部存款和储蓄器分布使用状态和堆解析的工具,不过jhat是放置的,是深入分析的一个好的早先。

……

3、jmap

jmap 是一个内部存款和储蓄器映射工具,它提供了其余一种没有供给吸引 OutOfMemoryErrors
就足以博得堆 dump 文件的诀要。大家多少改革一下地点的程序看一下作用。

public class OhMyMemory {

 private static Map map = new HashMap<>();

 public static void main(String[] args) {
   Runtime.getRuntime().addShutdownHook(
     new Thread() {
       @Override
       public void run() {
         try {
           System.out.println("Enter something, so I'll release the process");
           System.in.read();
           System.out.println("We have accumulated " + map.size() + " entries");
         }
         catch (IOException e) {
           e.printStackTrace();
         }
       }
     }
   );

   for(int i = 0; i < 10000 ;i++) {
     map.put(Integer.toBinaryString(i), i);
   }
 }
}

在乎,未来我们绝不消耗多量的内部存款和储蓄器,只是比较早竣工并在经过关闭钩子里等候不让
JVM 退出。这样就允许我们用 jmap 连接那么些历程得到高昂的内存 dump。

之所以你能够用 jmap 的多少个职能来贯彻,获取堆总结音讯和接触叁个堆
dump。由此,当实施:

jmap -heap 1354(这里 1354
是上面程序运营的历程号),就能够取得叁个很好的内部存款和储蓄器使用总计信息:

$ jmap -heap 1354                                                                                                                   
Attaching to process ID 1354, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.0-b70

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

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 67108864 (64.0MB)
   NewSize                  = 1572864 (1.5MB)
   MaxNewSize               = 22020096 (21.0MB)
   OldSize                  = 45088768 (43.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 = 1048576 (1.0MB)
   used     = 628184 (0.5990829467773438MB)
   free     = 420392 (0.40091705322265625MB)
   59.908294677734375% used
From Space:
   capacity = 524288 (0.5MB)
   used     = 491568 (0.4687957763671875MB)
   free     = 32720 (0.0312042236328125MB)
   93.7591552734375% used
To Space:
   capacity = 524288 (0.5MB)
   used     = 0 (0.0MB)
   free     = 524288 (0.5MB)
   0.0% used
PS Old Generation
   capacity = 45088768 (43.0MB)
   used     = 884736 (0.84375MB)
   free     = 44204032 (42.15625MB)
   1.9622093023255813% used

981 interned Strings occupying 64824 bytes.

$ jmap -dump:live,format=b,file=heap.bin 1354                                                                               
Dumping heap to /Users/shelajev/workspace_idea/throwaway/heap.bin ...
Heap dump file created

jmap 还足以大致地接触当前堆
dump,之后能够随性所欲进行拆解剖析。你能够像上面例子中的那样,传一个 -dump
参数给 jmap。

至今有了 dump 获得的文件 heap.bin,就可以用你心爱的内部存款和储蓄器剖判工具来深入分析。

这个难题在平凡支付中也许被许三个人忽略(例如某一个人高出上边包车型大巴标题只是重启服务器也许调大内部存储器,而不会根究难点根源),但亦可清楚并减轻那一个标题是Java程序猿升级的必备须求。

4、jps

jps 是显得 Java
程序系统经过(PID)最常用的工具。它与平台无关,蛮好用。想象一下我们运营了地点的次第,然后想用
jmap 连接它。当时大家须求程序的 PID,jps 赶巧的派上用项。

$ jps -mlv
5911 com.intellij.rt.execution.application.AppMain org.shelajev.throwaway.jdktools.OhMyMemory -Xmx64m -Didea.launcher.port=7535 -Didea.launcher.bin.path=/Applications/IntelliJ IDEA 14 EAP.app/Contents/bin -Dfile.encoding=UTF-8
5544  -Dfile.encoding=UTF-8 -ea -Dsun.io.useCanonCaches=false -Djava.net.preferIPv4Stack=true -Djsse.enableSNIExtension=false -XX:+UseConcMarkSweepGC -XX:SoftRefLRUPolicyMSPerMB=50 -XX:+HeapDumpOnOutOfMemoryError -Xverify:none -Xbootclasspath/a:../lib/boot.jar -Xms128m -Xmx750m -XX:MaxPermSize=350m -XX:ReservedCodeCacheSize=225m -XX:+UseCompressedOops -agentlib:yjpagent=probe_disable=*,disablealloc,disabletracing,onlylocal,disableexceptiontelemetry,delay=10000,sessionname=IntelliJIdea14 -Didea.java.redist=NoJavaDistribution -Didea.home.path=/Applications/IntelliJ IDEA 14 EAP.app/Contents -Didea.paths.selector=IntelliJIdea14
5930 sun.tools.jps.Jps -mlvV -Dapplication.home=/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home -Xms8m

咱俩开采超多场所下,“-mlv”
参数组合起来最棒用。它会打字与印刷main方法的参数、完整包名、JVM
相关参数。那样你就足以在一大堆相像的进度中找到你想要的十一分。

这段时间有了 dump 得到的文件 heap.bin,就足以用你喜爱的内部存款和储蓄器深入分析工具来深入分析。


5、jstack

jstack 是一个浮动钦命 JVM
进度的线程货仓工具。当您程序平昔在此边转圈圈,而你想找到线程到底做了何等引致死锁,那么
jstack 最相符。

jstack
唯有多少个参数选项,要是您拿不允许,把它们都增加。借使前边发掘存些音信对您意义十分小时能够调动参数约束它的输出。

-F 选项能够用来强逼 dump,那在经过挂起时极其有用,-I
选项能够打印同步和锁的音讯。

$ jstack -F -l 9153
Attaching to process ID 9153, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.0-b70
Deadlock Detection:

No deadlocks found.
….

地点的出口即使看起来轻易,可是它包涵了各样线程的情形和它这段时间的商旅的新闻。

jstack
非经常有用,大家在普通职业中应用特别频繁,极其是大家承当运行结束应用服务器的测验引擎。测量试验专业每每不顺手,jstack
能够让大家精晓 JVM 内部的运转状态且从未什么样消极的一面包车型地铁震慑。

— Neeme Praks(ZeroTurnaround资深成品技术员)

A、 jps(Java Virtual Machine Process Status Tool)

还大概有任何的啊?

后天我们介绍了 JDK
发行预装的超屌工具。相信本人,现在某天你势必会用到它们中的一些。所以,假诺您不时光,你能够翻一翻它们的合希腊语档。

试着在分歧的情景使用并爱上它们。

一旦你想学一些好屌的非 JDK 附带的工具,能够看看 JRebel
,它能够让你即刻见到代码的转移效果,还足以见见大家新的产物 XRebel
,它可以像X光老花镜雷同扫描你的 web 应用。

如若您明白开拓最棒实行中言行若一的小工具,在本文末尾发布讨论只怕在
twitter上@shelajev 分享一下以此工具的细节。

jps首要用以输出JVM中运作的进度景况音信。语法格式如下:

Bonus Section: References

奖赏环节:参照他事他说加以考察

下边是一个越发完整的 JDK
工具可用列表。尽管那不是一个完完全全的列表,为了省去篇幅,我们省掉了加密、web-services
相关的工具等。多谢 manpagez.com 提供的财富。

  • jar — 七个成立和治本 jar
    文件的工具。
  • java — Java
    应用运行器。在此篇文章里,开辟和布置都以用的那么些运转器。
  • javac — Java 编译器。
  • javadoc — API 文书档案生成器。
  • javah — native
    当地点法中用于生成 C 语言头文件和源文件。
  • javap — class 文件反编写翻译器。
  • jcmd — JVM
    命令行诊断工具,可发送确诊命令伏乞到 JVM 中。
  • jconsole — 三个同盟 JMX
    的监察 JVM 的图形化学工业具。能够监督本地和远程
    JVM,也能够监察和控制和保管单独的三个施用。
  • jdb — Java 调试器。
  • jps — JVM
    进程查看工具,列出了系统运作的有所 hotspot JVM 进程。
  • jstat — JVM 状态监察工具。它能够采撷和打印钦命的
    JVM 进度质量状态。
  • jhat — 堆 dump
    新闻的浏览器,运转二个 web 服务器来显示你用诸如 jmap -dump 获得的堆
    dump 音讯。
  • jmap — Java
    内部存款和储蓄器映射工具,打字与印刷钦点进度、大旨文件、远程调节和测验服务器分享内部存款和储蓄器映射或许堆内部存款和储蓄器详细新闻。
  • jsadebugd — Java
    服务调节和测量检验守护进度—依附到二个 Java
    进程或骨干文件同一时间担当一个调节和测量试验服务器的法力。
  • jstack —Java
    仓库消息工具——打印内定进度或宗旨文件或许远程调节和测量检验服务器的线程旅社。
  • jjs — 运转Nashorn 命令行脚本 shell。
  • jrunscript
    — Java
    脚本运转为工人身份具。不过你要心里有数,那件事实上是三个尚未扶植的测量检验作用。以后的
    JDK 版本里面或者会移除它。

可望上边的剧情对你们有赞助,你能够在 twitter 上 @
shelajev贪滥无厌你宝贵的评价。若是您精通有些自己从未谈到的珍视工具,请让本人晓得。

jps [options] [hostid]

万一不钦定hostid就默感到方今主机或服务器。

命令行参数选项表明如下:

-q 不出口类名、Jar名和散播main方法的参数

-m 输出传入main方法的参数

-l 输出main类或Jar的全限名

-v 输出传入JVM的参数

举个例子说上边:

root@ubuntu:/# jps -m -l
2458 org.artifactory.standalone.main.Main /usr/local/artifactory-2.2.5/etc/jetty.xml
29920 com.sun.tools.hat.Main -port 9998 /tmp/dump.dat
3149 org.apache.catalina.startup.Bootstrap start
30972 sun.tools.jps.Jps -m -l
8247 org.apache.catalina.startup.Bootstrap start
25687 com.sun.tools.hat.Main -port 9999 dump.dat
21711 mrf-center.jar

B、 jstack

jstack首要用来查看有个别Java进度内的线程客栈信息。语法格式如下:

jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip

命令行参数选项表明如下:

-l long listings,会打字与印刷出额外的锁信息,在发出死锁时能够用jstack -l
pid来观看锁持有状态

-m mixed
mode,不仅仅会输出Java仓库新闻,还大概会输出C/C++仓库消息(譬喻Native方法)

jstack可以固定到线程宾馆,依据仓库音讯我们得以一定到现实代码,所以它在JVM质量调优中运用得那么些多。上面大家来八个实例找寻有些Java进度中最花费CPU的Java线程并定位货仓音信,用到的授命有ps、top、printf、jstack、grep。

先是步先寻找Java进程ID,服务器上的Java应用名为mrf-center:

root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep
root     21711     1  1 14:47 pts/3    00:02:10 java -jar mrf-center.jar

得到进程ID为21711,第二步找寻该进度内最花销CPU的线程,能够应用

1)ps -Lfp pid
2)ps -mp pid -o THREAD, tid, time
3)top -Hp pid

用第七个,输出如下:

澳门新葡萄京官网首页 6

TIME列就是逐个Java线程花销的CPU时间,CPU时间最长的是线程ID为21742的线程,用

printf "%xn" 21742

收获21742的十七进制值为54ee,下边会用到。

OK,下一步终于轮到jstack上台了,它用来输出进程21711的堆栈新闻,然后根据线程ID的十五进制值grep,如下:

root@ubuntu:/# jstack 21711 | grep 54ee
"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait()

能够看来CPU消耗在PollIntervalRetrySchedulerThread那一个类的Object.wait(卡塔尔国,小编找了下自家的代码,定位到下边包车型大巴代码:

// Idle wait
getLog().info("Thread [" + getName() + "] is idle waiting...");
schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting;
long now = System.currentTimeMillis();
long waitTime = now + getIdleWaitTime();
long timeUntilContinue = waitTime - now;
synchronized(sigLock) {
  try {
    if(!halted.get()) {
      sigLock.wait(timeUntilContinue);
    }
  } 
  catch (InterruptedException ignore) {
  }
}

它是轮询任务的悠闲等待代码,上边的sigLock.wait(timeUntilContinueState of Qatar就对应了前面包车型客车Object.wait(卡塔尔(قطر‎。

C、 jmap(Memory Map)和jhat(Java Heap Analysis Tool)

jmap用来查看堆内部存款和储蓄器使用情状,经常结合jhat使用。

jmap语法格式如下:

jmap [option] pid
jmap [option] executable core
jmap [option] [server-id@]remote-hostname-or-ip

就算运维在60位JVM上,恐怕供给内定-J-d64下令选项参数。

jmap -permstat pid

打字与印刷进度的类加载器和类加载器加载的长久代对象音讯,输出:类加载器名称、对象是不是存活(不可靠)、对象地址、父类加载器、已加载的类大小等音讯,如下图:

动用jmap -heap
pid查看进度堆内部存款和储蓄器使用境况,包涵运用的GC算法、堆配置参数和各代中堆内部存储器使用情形。
举例上面包车型大巴事例

root@ubuntu:/# jmap -heap 21711
Attaching to process ID 21711, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 20.10-b01

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

Heap Configuration:
  MinHeapFreeRatio = 40
  MaxHeapFreeRatio = 70
  MaxHeapSize       = 2067791872 (1972.0MB)
  NewSize            = 1310720 (1.25MB)
  MaxNewSize         = 17592186044415 MB
  OldSize            = 5439488 (5.1875MB)
  NewRatio          = 2
  SurvivorRatio  = 8
  PermSize          = 21757952 (20.75MB)
  MaxPermSize       = 85983232 (82.0MB)

Heap Usage:
PS Young Generation
Eden Space:
  capacity = 6422528 (6.125MB)
  used    = 5445552 (5.1932830810546875MB)
  free    = 976976 (0.9317169189453125MB)
  84.78829520089286% used
From Space:
  capacity = 131072 (0.125MB)
  used    = 98304 (0.09375MB)
  free    = 32768 (0.03125MB)
  75.0% used
To Space:
  capacity = 131072 (0.125MB)
  used    = 0 (0.0MB)
  free    = 131072 (0.125MB)
  0.0% used
PS Old Generation
  capacity = 35258368 (33.625MB)
  used    = 4119544 (3.9287033081054688MB)
  free    = 31138824 (29.69629669189453MB)
  11.683876009235595% used
PS Perm Generation
  capacity = 52428800 (50.0MB)
  used    = 26075168 (24.867218017578125MB)
  free    = 26353632 (25.132781982421875MB)
  49.73443603515625% used
  ....

使用jmap -histo[:live]
pid查看堆内存中的目的数目、大小总计直方图,若是带上live则只总计活对象,如下:

root@ubuntu:/# jmap -histo:live 21711 | more

 num      #instances            #bytes  class name
----------------------------------------------
  1:            38445         5597736  
  2:            38445         5237288  
  3:             3500         3749504  
  4:            60858         3242600  
  5:             3500         2715264  
  6:             2796         2131424  
  7:             5543         1317400  [I
  8:            13714         1010768  [C
  9:             4752         1003344  [B
  10:            1225           639656  
  11:           14194           454208  java.lang.String
  12:            3809           396136  java.lang.Class
  13:            4979           311952  [S
  14:            5598           287064  [[I
  15:            3028           266464  java.lang.reflect.Method
  16:             280           163520  
  17:            4355           139360  java.util.HashMap$Entry
  18:            1869           138568  [Ljava.util.HashMap$Entry;
  19:            2443            97720  java.util.LinkedHashMap$Entry
  20:            2072            82880  java.lang.ref.SoftReference
  21:            1807            71528  [Ljava.lang.Object;
  22:            2206            70592  java.lang.ref.WeakReference
  23:             934            52304  java.util.LinkedHashMap
  24:             871            48776  java.beans.MethodDescriptor
  25:            1442            46144  java.util.concurrent.ConcurrentHashMap$HashEntry
  26:             804            38592  java.util.HashMap
  27:             948            37920  java.util.concurrent.ConcurrentHashMap$Segment
  28:            1621            35696  [Ljava.lang.Class;
  29:            1313            34880  [Ljava.lang.String;
  30:            1396            33504  java.util.LinkedList$Entry
  31:             462            33264  java.lang.reflect.Field
  32:            1024            32768  java.util.Hashtable$Entry
  33:             948            31440  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;

class name是目的类型,表达如下:

B  byte
C  char
D  double
F  float
I  int
J  long
Z  boolean
[  数组,如[I表示int[]
[L+类名 其他对象

还会有一个很常用的气象是:用jmap把经过内部存款和储蓄器使用境况dump到文件中,再用jhat深入分析查看。jmap实行dump命令格式如下:

jmap -dump:format=b,file=dumpFileName pid

本身相同地对上边进度ID为21711进展Dump:

root@ubuntu:/# jmap -dump:format=b,file=/tmp/dump.dat 21711     
Dumping heap to /tmp/dump.dat ...
Heap dump file created

dump出来的文本可以用MAT、VisualVM等工具查看,这里用jhat查看:

root@ubuntu:/# jhat -port 9998 /tmp/dump.dat
Reading from /tmp/dump.dat...
Dump file created Tue Jan 28 17:46:14 CST 2014
Snapshot read, resolving...
Resolving 132207 objects...
Chasing references, expect 26 dots..........................
Eliminating duplicate references..........................
Snapshot resolved.
Started HTTP server on port 9998
Server is ready.

在乎假如Dump文件太大,只怕供给增加-J-Xmx512m这种参数钦点最大堆内部存款和储蓄器,即jhat
-J-Xmx512m -port 9998
/tmp/dump.dat。然后就足以在浏览器中输入主机地址:9998查看了:

澳门新葡萄京官网首页 7

地点红线框出来的局地我们能够和睦去搜求下,最终一项辅助OQL(对象查询语言)。

D、 jstat(JVM总计监测工具)

语法格式如下:

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

vmid是Java虚拟机ID,在Linux/Unix系统上日常就是经过ID。interval是采样时间隔断。count是采集样板数目。举个例子上面输出的是GC音信,采集样板时间隔离为250ms,采集样本数为4:

root@ubuntu:/# jstat -gc 21711 250 4
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT   
192.0  192.0   64.0   0.0    6144.0   1854.9   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649
192.0  192.0   64.0   0.0    6144.0   1972.2   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649
192.0  192.0   64.0   0.0    6144.0   1972.2   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649
192.0  192.0   64.0   0.0    6144.0   2109.7   32000.0     4111.6   55296.0 25472.7    702    0.431   3      0.218    0.649

要知道上边各列的含义,先看JVM堆内部存款和储蓄器布局:

能够看见:

堆内存 = 年轻代 + 年老代 + 永久代
年轻代 = Eden区 + 两个Survivor区(From和To)

近年来来解释各列含义:

S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)
EC、EU:Eden区容量和使用量
OC、OU:年老代容量和使用量
PC、PU:永久代容量和使用量
YGC、YGT:年轻代GC次数和GC耗时
FGC、FGCT:Full GC次数和Full GC耗时
GCT:GC总耗时
E、hprof(Heap/CPU Profiling Tool)

hprof能够呈现CPU使用率,总括堆内部存款和储蓄器使用情状。

语法格式如下:

java -agentlib:hprof[=options] ToBeProfiledClass
java -Xrunprof[:options] ToBeProfiledClass
javac -J-agentlib:hprof[=options] ToBeProfiledClass

完整的吩咐选项如下:

Option Name and Value  Description                    Default
---------------------  -----------                    -------
heap=dump|sites|all    heap profiling                 all
cpu=samples|times|old  CPU usage                      off
monitor=y|n            monitor contention             n
format=a|b             text(txt) or binary output     a
file=            write data to file             java.hprof[.txt]
net=:      send data over a socket        off
depth=           stack trace depth              4
interval=          sample interval in ms          10
cutoff=         output cutoff point            0.0001
lineno=y|n             line number in traces?         y
thread=y|n             thread in traces?              n
doe=y|n                dump on exit?                  y
msa=y|n                Solaris micro state accounting n
force=y|n              force output to          y
verbose=y|n            print messages about dumps     y

来多少个官方指南上的实例。

CPU Usage Sampling Profiling(cpu=samples)的例子:

CPU Usage Sampling Profiling(cpu=samples)的例子:

java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello

  上面每隔20毫秒采样CPU消耗信息,堆栈深度为3,生成的profile文件名称是java.hprof.txt,在当前目录。 

  CPU Usage Times Profiling(cpu=times)的例子,它相对于CPU Usage Sampling Profile能够获得更加细粒度的CPU消耗信息,能够细到每个方法调用的开始和结束,它的实现使用了字节码注入技术(BCI):


javac -J-agentlib:hprof=cpu=times Hello.java

  Heap Allocation Profiling(heap=sites)的例子:


javac -J-agentlib:hprof=heap=sites Hello.java

  Heap Dump(heap=dump)的例子,它比上面的Heap Allocation Profiling能生成更详细的Heap Dump信息:

javac -J-agentlib:hprof=heap=dump Hello.java

  虽然在JVM启动参数中加入-Xrunprof:heap=sites参数可以生成CPU/Heap Profile文件,但对JVM性能影响非常大,不建议在线上服务器环境使用。

第二部分: 实例部分:

1、使用jstack来分析死锁难题:

上边表达中涉嫌jstack
是一个方可回到在应用程序上运维的有滋有味线程的一个完完全全转储的实用程序,您能够行使它查明难题。jstack
[-l]
,jpid能够经过应用jps命令来查阅当前Java程序的jpid值,-l是可选参数,它可以呈现线程梗塞/死锁境况

/**
 * Dead lock example
 * 
 * @author Josh Wang(Sheng)
 *
 * @email  josh_wang23@hotmail.com
 */
public class DeadLock2Live {  

  public static void main(String[] args) {  
    System.out.println(" start the example ----- ");
    final Object obj_1 = new Object(), obj_2 = new Object();  

    Thread t1 = new Thread("t1"){  
      @Override  
      public void run() {  
        synchronized (obj_1) {  
          try {  
            Thread.sleep(3000);  
          } catch (InterruptedException e) {}  

          synchronized (obj_2) {  
            System.out.println("thread t1 done.");  
          }  
        }  
      }  
    };  

    Thread t2 = new Thread("t2"){  
      @Override  
      public void run() {  
        synchronized (obj_2) {  
          try {  
            Thread.sleep(3000);  
          } catch (InterruptedException e) {}  

          synchronized (obj_1) {  
            System.out.println("thread t2 done.");  
          }  
        }  
      }  
    };  

    t1.start();  
    t2.start();  
  }  

}

以上DeadLock类是一个死锁的事例,若是在大家不知情的情事下,运行DeadLock后,发掘等了N久都不曾经在荧屏打印线程完毕新闻。当时我们就足以采用jps查看该程序的jpid值和平运动用jstack来临蓐仓库结果难点。

java -cp deadlock.jar DeadLock &


$ jps  
  3076 Jps  
  448 DeadLock  
$ jstack -l 448 > deadlock.jstack

结果文件deadlock.jstack内容如下:

2014-11-29 13:31:06
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode):

"Attach Listener" daemon prio=5 tid=0x00007fd9d4002800 nid=0x440b waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"DestroyJavaVM" prio=5 tid=0x00007fd9d4802000 nid=0x1903 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"t2" prio=5 tid=0x00007fd9d30ac000 nid=0x5903 waiting for monitor entry [0x000000011da46000]
  java.lang.Thread.State: BLOCKED (on object monitor)
  at DeadLock$2.run(DeadLock.java:38)
  - waiting to lock <0x00000007aaba7e58> (a java.lang.Object)
  - locked <0x00000007aaba7e68> (a java.lang.Object)

  Locked ownable synchronizers:
  - None

"t1" prio=5 tid=0x00007fd9d30ab800 nid=0x5703 waiting for monitor entry [0x000000011d943000]
  java.lang.Thread.State: BLOCKED (on object monitor)
  at DeadLock$1.run(DeadLock.java:23)
  - waiting to lock <0x00000007aaba7e68> (a java.lang.Object)
  - locked <0x00000007aaba7e58> (a java.lang.Object)

  Locked ownable synchronizers:
  - None

"Service Thread" daemon prio=5 tid=0x00007fd9d2809000 nid=0x5303 runnable [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"C2 CompilerThread1" daemon prio=5 tid=0x00007fd9d304e000 nid=0x5103 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"C2 CompilerThread0" daemon prio=5 tid=0x00007fd9d2800800 nid=0x4f03 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"Signal Dispatcher" daemon prio=5 tid=0x00007fd9d3035000 nid=0x4d03 runnable [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"Finalizer" daemon prio=5 tid=0x00007fd9d2013000 nid=0x3903 in Object.wait() [0x000000011d18d000]
  java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x00000007aaa85608> (a java.lang.ref.ReferenceQueue$Lock)
  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
  - locked <0x00000007aaa85608> (a java.lang.ref.ReferenceQueue$Lock)
  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
  at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

  Locked ownable synchronizers:
  - None

"Reference Handler" daemon prio=5 tid=0x00007fd9d2012000 nid=0x3703 in Object.wait() [0x000000011d08a000]
  java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x00000007aaa85190> (a java.lang.ref.Reference$Lock)
  at java.lang.Object.wait(Object.java:503)
  at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
  - locked <0x00000007aaa85190> (a java.lang.ref.Reference$Lock)

  Locked ownable synchronizers:
  - None

"VM Thread" prio=5 tid=0x00007fd9d5011000 nid=0x3503 runnable 

"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007fd9d200b000 nid=0x2503 runnable 

"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007fd9d200b800 nid=0x2703 runnable 

"GC task thread#2 (ParallelGC)" prio=5 tid=0x00007fd9d200c800 nid=0x2903 runnable 

"GC task thread#3 (ParallelGC)" prio=5 tid=0x00007fd9d200d000 nid=0x2b03 runnable 

"GC task thread#4 (ParallelGC)" prio=5 tid=0x00007fd9d200d800 nid=0x2d03 runnable 

"GC task thread#5 (ParallelGC)" prio=5 tid=0x00007fd9d200e000 nid=0x2f03 runnable 

"GC task thread#6 (ParallelGC)" prio=5 tid=0x00007fd9d200f000 nid=0x3103 runnable 

"GC task thread#7 (ParallelGC)" prio=5 tid=0x00007fd9d200f800 nid=0x3303 runnable 

"VM Periodic Task Thread" prio=5 tid=0x00007fd9d3033800 nid=0x5503 waiting on condition 

JNI global references: 114


Found one Java-level deadlock:
=============================
"t2":
  waiting to lock monitor 0x00007fd9d30aebb8 (object 0x00000007aaba7e58, a java.lang.Object),
  which is held by "t1"
"t1":
  waiting to lock monitor 0x00007fd9d28128b8 (object 0x00000007aaba7e68, a java.lang.Object),
  which is held by "t2"

Java stack information for the threads listed above:
===================================================
"t2":
  at DeadLock$2.run(DeadLock.java:38)
  - waiting to lock <0x00000007aaba7e58> (a java.lang.Object)
  - locked <0x00000007aaba7e68> (a java.lang.Object)
"t1":
  at DeadLock$1.run(DeadLock.java:23)
  - waiting to lock <0x00000007aaba7e68> (a java.lang.Object)
  - locked <0x00000007aaba7e58> (a java.lang.Object)

Found 1 deadlock.

从那几个结果文件我们一见到发掘了两个死锁,具体是线程t2在等待线程t1,而线程t1在等待线程t2形成的,同有时间也记录了线程的库房和代码行数,通过这么些库房和行数大家就足以去检核查应的代码块,进而开采标题和解决难题。

可透过下边包车型大巴代码化解死锁难点:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Dead lock example
 * 
 * @author Josh Wang(Sheng)
 *
 * @email  josh_wang23@hotmail.com
 */
public class DeadLock2Live {  

  public static void main(String[] args) {  
    System.out.println(" start the example ----- ");
    final Lock lock = new ReentrantLock(); 

    Thread t1 = new Thread("t1") {  
      @Override  
      public void run() {  
        try {  
            lock.lock();
          Thread.sleep(3000); 
          System.out.println("thread t1 done.");
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();
        }
      }
      };  

    Thread t2 = new Thread("t2") {  
      @Override  
      public void run() {  
        try {  
          lock.lock();
          Thread.sleep(3000);
          System.out.println("thread t2 done.");


        }  catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();
        }
      }  
    };  

    t1.start();  
    t2.start();  

}

}

2、继续采纳jstack来解析HashMap在多线程境况下的死锁难点:

对于如下代码,使用十三个线程来管理提交的2001个任务,每一种职责会分别循环往hashmap中分别存入和抽出1000个数,通过测量试验开采,程序并不可能完好施行到位。[PS:该程序能或不可能学有所成推行完,有时也可以有赖于所使用的服务器的运维处境,小编在记录本上测验的时候,多数时候该程序不可能得逞进行到位,前面一个会并发CPU转速加速,发热等情状]

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 
 */

/**
 * @author Josh Wang(Sheng)
 *
 * @email  josh_wang23@hotmail.com
 */
public class HashMapDeadLock implements Callable {

  private static ExecutorService threadPool = Executors.newFixedThreadPool(10);

  private static Map results = new HashMap<>();

  @Override
  public Integer call() throws Exception {
    results.put(1, 1);
    results.put(2, 2);
    results.put(3, 3);

    for (int i = 0; i < 1000; i++) {
      results.put(i, i);
    }

    Thread.sleep(1000);

    for (int i= 0; i < 1000; i++) {
      results.remove(i);
    }

    System.out.println(" ---- " + Thread.currentThread().getName()  + "     " + results.get(0));

    return results.get(1);
  }


  public static void main(String[] args) throws InterruptedException, ExecutionException {
    try {
      for (int i = 0; i < 2000; i++) {
          HashMapDeadLock hashMapDeadLock  = new HashMapDeadLock();
//                  Future future = threadPool.submit(hashMapDeadLock);
//                  future.get();
          threadPool.submit(hashMapDeadLock);
        }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      threadPool.shutdown();
    }




  }


}

1) 使用jps查看线程可得:

43221 Jps
30056 
43125 HashMapDeadLock

2)使用jstack导出四线程栈区音信:

jstack -l 43125 > hash.jstack
  • 1

3卡塔尔国 hash.jstack的内容如下:

2014-11-29 18:14:22
Full thread dump Java HotSpot(TM) 64-Bit Server VM (24.65-b04 mixed mode):

"Attach Listener" daemon prio=5 tid=0x00007f83ee08a000 nid=0x5d07 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"DestroyJavaVM" prio=5 tid=0x00007f83eb016800 nid=0x1903 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"pool-1-thread-10" prio=5 tid=0x00007f83ec80a000 nid=0x6903 runnable [0x000000011cd19000]
  java.lang.Thread.State: RUNNABLE
  at java.util.HashMap.transfer(HashMap.java:601)
  at java.util.HashMap.resize(HashMap.java:581)
  at java.util.HashMap.addEntry(HashMap.java:879)
  at java.util.HashMap.put(HashMap.java:505)
  at HashMapDeadLock.call(HashMapDeadLock.java:30)
  at HashMapDeadLock.call(HashMapDeadLock.java:1)
  at java.util.concurrent.FutureTask.run(FutureTask.java:262)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
  at java.lang.Thread.run(Thread.java:745)

  Locked ownable synchronizers:
  - <0x00000007aaba84c8> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"Service Thread" daemon prio=5 tid=0x00007f83eb839800 nid=0x5303 runnable [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"C2 CompilerThread1" daemon prio=5 tid=0x00007f83ee002000 nid=0x5103 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"C2 CompilerThread0" daemon prio=5 tid=0x00007f83ee000000 nid=0x4f03 waiting on condition [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"Signal Dispatcher" daemon prio=5 tid=0x00007f83ec04c800 nid=0x4d03 runnable [0x0000000000000000]
  java.lang.Thread.State: RUNNABLE

  Locked ownable synchronizers:
  - None

"Finalizer" daemon prio=5 tid=0x00007f83eb836800 nid=0x3903 in Object.wait() [0x000000011bc58000]
  java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x00000007aaa85608> (a java.lang.ref.ReferenceQueue$Lock)
  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
  - locked <0x00000007aaa85608> (a java.lang.ref.ReferenceQueue$Lock)
  at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
  at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

  Locked ownable synchronizers:
  - None

"Reference Handler" daemon prio=5 tid=0x00007f83eb01a800 nid=0x3703 in Object.wait() [0x000000011bb55000]
  java.lang.Thread.State: WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  - waiting on <0x00000007aaa85190> (a java.lang.ref.Reference$Lock)
  at java.lang.Object.wait(Object.java:503)
  at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
  - locked <0x00000007aaa85190> (a java.lang.ref.Reference$Lock)

  Locked ownable synchronizers:
  - None

"VM Thread" prio=5 tid=0x00007f83ed808800 nid=0x3503 runnable 

"GC task thread#0 (ParallelGC)" prio=5 tid=0x00007f83ec80d800 nid=0x2503 runnable 

"GC task thread#1 (ParallelGC)" prio=5 tid=0x00007f83ec80e000 nid=0x2703 runnable 

"GC task thread#2 (ParallelGC)" prio=5 tid=0x00007f83ec001000 nid=0x2903 runnable 

"GC task thread#3 (ParallelGC)" prio=5 tid=0x00007f83ec002000 nid=0x2b03 runnable 

"GC task thread#4 (ParallelGC)" prio=5 tid=0x00007f83ec002800 nid=0x2d03 runnable 

"GC task thread#5 (ParallelGC)" prio=5 tid=0x00007f83ec003000 nid=0x2f03 runnable 

"GC task thread#6 (ParallelGC)" prio=5 tid=0x00007f83ec003800 nid=0x3103 runnable 

"GC task thread#7 (ParallelGC)" prio=5 tid=0x00007f83ec004800 nid=0x3303 runnable 

"VM Periodic Task Thread" prio=5 tid=0x00007f83ec814800 nid=0x5503 waiting on condition 

JNI global references: 134

4)从灰黄高亮部分可观看,代码中的30行出标题了,即往hashmap中写入数据出难点了:

results.put(i, i);

神速就精晓因为Hashmap不是线程安全的,所以难点就出在此个地点,我们能够动用线程安全的map即

ConcurrentHashMap后面一个HashTable来减轻该难题:

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 
 */

/**
 * @author Josh Wang(Sheng)
 *
 * @email  josh_wang23@hotmail.com
 */
public class HashMapDead2LiveLock implements Callable {

  private static ExecutorService threadPool = Executors.newFixedThreadPool(10);

  private static Map results = new ConcurrentHashMap<>();

  @Override
  public Integer call() throws Exception {
    results.put(1, 1);
    results.put(2, 2);
    results.put(3, 3);

    for (int i = 0; i < 1000; i++) {
      results.put(i, i);
    }

    Thread.sleep(1000);

    for (int i= 0; i < 1000; i++) {
      results.remove(i);
    }

    System.out.println(" ---- " + Thread.currentThread().getName()  + "     " + results.get(0));

    return results.get(1);
  }


  public static void main(String[] args) throws InterruptedException, ExecutionException {
    try {
      for (int i = 0; i < 2000; i++) {
          HashMapDead2LiveLock hashMapDeadLock  = new HashMapDead2LiveLock();
//                  Future future = threadPool.submit(hashMapDeadLock);
//                  future.get();
          threadPool.submit(hashMapDeadLock);
        }
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      threadPool.shutdown();
    }




  }


}

改成ConcurrentHashMap后,重新实施该程序,你会发觉高速该程序就实践完了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注