<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          JVM 性能調(diào)優(yōu)監(jiān)控工具 jps、jstack、jmap、jhat、jstat、hprof 使用詳解

          共 10596字,需瀏覽 22分鐘

           ·

          2021-08-13 22:28

          從前我們都想翻越高山

          到達(dá)世界的最頂峰

          證明一世的驕傲

          時過境遷,才發(fā)覺偶爾躺平也是一種智慧

          這個世界真的沒有我們的夢想?

          這個時代最值得學(xué)習(xí)的就是:投資

          投資也許會短暫虧損,但是會從中洞見一個新世界

          然后最終變成財富

          這個世界唯一不變的真理:便是實(shí)踐

          不要以為在這里開戶就好像占了便宜

          那不過是交了一個真摯的朋友

          掃碼在線港美股開戶


          長按掃描上方購買

           本文來源:www.iteye.com/blog/josh-persistence-2161848


          現(xiàn)實(shí)企業(yè)級Java應(yīng)用開發(fā)、維護(hù)中,有時候我們會碰到下面這些問題:

          • OutOfMemoryError,內(nèi)存不足
          • 內(nèi)存泄露
          • 線程死鎖
          • 鎖爭用(Lock Contention)
          • Java進(jìn)程消耗CPU過高
          • ......

          這些問題在日常開發(fā)、維護(hù)中可能被很多人忽視(比如有的人遇到上面的問題只是重啟服務(wù)器或者調(diào)大內(nèi)存,而不會深究問題根源),但能夠理解并解決這些問題是Java程序員進(jìn)階的必備要求。

          本文將對一些常用的JVM性能調(diào)優(yōu)監(jiān)控工具進(jìn)行介紹,希望能起拋磚引玉之用。

          一、 jps(Java Virtual Machine Process Status Tool)      :基礎(chǔ)工具   

          jps主要用來輸出JVM中運(yùn)行的進(jìn)程狀態(tài)信息。語法格式如下:


          jps [options] [hostid]


          如果不指定hostid就默認(rèn)為當(dāng)前主機(jī)或服務(wù)器。


          命令行參數(shù)選項說明如下:


          -q 不輸出類名、Jar名和傳入main方法的參數(shù)

          -m 輸出傳入main方法的參數(shù)

          -l 輸出main類或Jar的全限名

          -v 輸出傳入JVM的參數(shù)


          比如下面:


          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


          二、 jstack    


          jstack主要用來查看某個Java進(jìn)程內(nèi)的線程堆棧信息。語法格式如下:


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


          命令行參數(shù)選項說明如下:


          -l long listings,會打印出額外的鎖信息,在發(fā)生死鎖時可以用jstack -l pid來觀察鎖持有情況-m mixed mode,不僅會輸出Java堆棧信息,還會輸出C/C++堆棧信息(比如Native方法)


          jstack可以定位到線程堆棧,根據(jù)堆棧信息我們可以定位到具體代碼,所以它在JVM性能調(diào)優(yōu)中使用得非常多。

          下面我們來一個實(shí)例找出某個Java進(jìn)程中最耗費(fèi)CPU的Java線程并定位堆棧信息,用到的命令有ps、top、printf、jstack、grep。

          第一步先找出Java進(jìn)程ID,我部署在服務(wù)器上的Java應(yīng)用名稱為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


          得到進(jìn)程ID為21711,第二步找出該進(jìn)程內(nèi)最耗費(fèi)CPU的線程,可以使用ps -Lfp pid或者ps -mp pid -o THREAD, tid, time或者top -Hp pid,我這里用第三個,輸出如下:



          TIME列就是各個Java線程耗費(fèi)的CPU時間,CPU時間最長的是線程ID為21742的線程,用


          printf "%x
          "
          21742


          得到21742的十六進(jìn)制值為54ee,下面會用到。   

          OK,下一步終于輪到j(luò)stack上場了,它用來輸出進(jìn)程21711的堆棧信息,然后根據(jù)線程ID的十六進(jìn)制值grep,如下:


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


          可以看到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) {
          }
          }


          它是輪詢?nèi)蝿?wù)的空閑等待代碼,上面的sigLock.wait(timeUntilContinue)就對應(yīng)了前面的Object.wait()。

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

          jmap導(dǎo)出堆內(nèi)存,然后使用jhat來進(jìn)行分析,jmap語法格式如下:


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


          如果運(yùn)行在64位JVM上,可能需要指定-J-d64命令選項參數(shù)。


          jmap -permstat pid


          打印進(jìn)程的類加載器和類加載器加載的持久代對象信息,輸出:類加載器名稱、對象是否存活(不可靠)、對象地址、父類加載器、已加載的類大小等信息,如下圖:



          使用jmap -heap pid查看進(jìn)程堆內(nèi)存使用情況,包括使用的GC算法、堆配置參數(shù)和各代中堆內(nèi)存使用情況。比如下面的例子:


          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查看堆內(nèi)存中的對象數(shù)目、大小統(tǒng)計直方圖,如果帶上live則只統(tǒng)計活對象,如下:


          root@ubuntu:/# jmap -histo:live 21711 | more
          num #instances #bytes class name----------------------------------------------
          1: 38445 5597736 <constMethodKlass>
          2: 38445 5237288 <methodKlass>
          3: 3500 3749504 <constantPoolKlass>
          4: 60858 3242600 <symbolKlass>
          5: 3500 2715264 <instanceKlassKlass>
          6: 2796 2131424 <constantPoolCacheKlass>
          7: 5543 1317400 [I
          8: 13714 1010768 [C
          9: 4752 1003344 [B
          10: 1225 639656 <methodDataKlass>
          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 <objArrayKlassKlass>
          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
          [ 數(shù)組,如[I表示int[]
          [L+類名 其他對象


          還有一個很常用的情況是:用jmap把進(jìn)程內(nèi)存使用情況dump到文件中,再用jhat分析查看。jmap進(jìn)行dump命令格式如下:


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


          我一樣地對上面進(jìn)程ID為21711進(jìn)行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 2014Snapshot read, resolving...
          Resolving 132207 objects...
          Chasing references, expect 26 dots..........................
          Eliminating duplicate references..........................
          Snapshot resolved.
          Started HTTP server on port 9998Server is ready.


          注意如果Dump文件太大,可能需要加上-J-Xmx512m這種參數(shù)指定最大堆內(nèi)存,即jhat -J-Xmx512m -port 9998 /tmp/dump.dat。然后就可以在瀏覽器中輸入主機(jī)地址:9998查看了:



          上面紅線框出來的部分大家可以自己去摸索下,最后一項支持OQL(對象查詢語言)。

          四、jstat(JVM統(tǒng)計監(jiān)測工具): 

          看看各個區(qū)內(nèi)存和GC的情況

          語法格式如下:


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


          vmid是Java虛擬機(jī)ID,在Linux/Unix系統(tǒng)上一般就是進(jìn)程ID。interval是采樣時間間隔。count是采樣數(shù)目。比如下面輸出的是GC信息,采樣時間間隔為250ms,采樣數(shù)為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堆內(nèi)存布局:



          可以看出:


          堆內(nèi)存 = 年輕代 + 年老代 + 永久代
          年輕代 = Eden區(qū) + 兩個Survivor區(qū)(From和To)


          現(xiàn)在來解釋各列含義:


          S0C、S1C、S0U、S1U:Survivor 0/1區(qū)容量(Capacity)和使用量(Used)
          EC、EU:Eden區(qū)容量和使用量
          OC、OU:年老代容量和使用量
          PC、PU:永久代容量和使用量
          YGC、YGT:年輕代GC次數(shù)和GC耗時
          FGC、FGCT:Full GC次數(shù)和Full GC耗時
          GCT:GC總耗時


          五、hprof(Heap/CPU Profiling Tool):    


          hprof能夠展現(xiàn)CPU使用率,統(tǒng)計堆內(nèi)存使用情況。


          語法格式如下:


          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=<file> write data to file java.hprof[.txt]
          net=<host>:<port> send data over a socket off
          depth=<size> stack trace depth 4
          interval=<ms> sample interval in ms 10
          cutoff=<value> 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 <file> y
          verbose=y|n print messages about dumps y


          來幾個官方指南上的實(shí)例。


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


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


          上面每隔20毫秒采樣CPU消耗信息,堆棧深度為3,生成的profile文件名稱是java.hprof.txt,在當(dāng)前目錄。 

          CPU Usage Times Profiling(cpu=times)的例子,它相對于CPU Usage Sampling Profile能夠獲得更加細(xì)粒度的CPU消耗信息,能夠細(xì)到每個方法調(diào)用的開始和結(jié)束,它的實(shí)現(xiàn)使用了字節(jié)碼注入技術(shù)(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能生成更詳細(xì)的Heap Dump信息:


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


          雖然在JVM啟動參數(shù)中加入-Xrunprof:heap=sites參數(shù)可以生成CPU/Heap Profile文件,但對JVM性能影響非常大,不建議在線上服務(wù)器環(huán)境使用



          推薦閱讀:

          世界的真實(shí)格局分析,地球人類社會底層運(yùn)行原理

          不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

          企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

          論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

          華為干部與人才發(fā)展手冊(附PPT)

          企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

          【中臺實(shí)踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

          華為的數(shù)字化轉(zhuǎn)型方法論

          華為如何實(shí)施數(shù)字化轉(zhuǎn)型(附PPT)

          超詳細(xì)280頁Docker實(shí)戰(zhàn)文檔!開放下載

          華為大數(shù)據(jù)解決方案(PPT)

          瀏覽 59
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  女人天堂网在线 | 日皮视频色 | 免费操B视频 | 黄色电影小视频 | 国产精品福利一区二区 |