JVM引數主要有⼏種分類
前言
JVM引數解析與調優
JVM 全稱 Java Virtual Machine,Java程式編譯之後生成的.class檔案就是交由JVM執行,由JVM將.class檔案內容翻譯成對於系統可識別的機器語言,這就是Java之所以能一次編譯,到處執行。
JVM引數
JVM堆記憶體
整個堆大小 = 年輕代(Young Generation) + 年老代(Old Generation) + 持久代(Perm Area) JVM堆記憶體用與new建立的物件和陣列,棧記憶體則用於分配基礎型別變數和物件的引用,當程式執行到作用域外時,棧內引用將被釋放,而失去了引用地址的堆記憶體裡的物件則變為了垃圾,在未知時間被GC回收釋放記憶體;
堆記憶體構成圖:
-
-Xms 初始堆大小 預設實體記憶體的1/64(小於1GB)空餘堆大小小於40%時,JVM就會增大堆直到-Xmx的最大限制
-
-Xmx 最大堆大小 預設實體記憶體的1/4(小於1GB)空餘堆大小大於70%時,JVM就會減少堆直到-Xms的最小限制
我們可以通過將“-Xms”和“-Xmx”設定為相同大小來獲得一個固定大小的堆記憶體。 -Xms和-Xmx實際上是-XX:InitialHeapSize和-XX:MaxHeapSize的縮寫。我們也可以直接使用這兩個引數,它們所起得效果是一樣的
-
-Xmn 年輕代大小
-
-XX:NewSize 設定年輕代初始大小
-
-XX:MaxNewSize 年輕代最大值
-
-XX:PermSize 設置持久代初始值
-
-XX:MaxPermSize 設定持久代最大值
-
-Xss 每個執行緒堆疊大小 JDK5.0以後每個執行緒堆疊大小為1M,以前每個執行緒堆疊大小為256K,這個引數對影響比較大,需經過嚴格測試後進行調整
-
-XX:NewRatio 年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代) -XX:NewRatio=4表示年輕代與年老代所佔比值為1:4,年輕代佔整個堆疊的1/5,Xms=Xmx並且設定了Xmn的情況下,該引數不需要進行設定。
-
-XX:SurvivorRatio Eden區與Survivor區的大小比值 設定為8,則兩個Survivor區與一個Eden區的比值為2:8,一個Survivor區佔整個年輕代的1/10
-
-XX:+HeapDumpOnOutOfMemoryError and -XX:HeapDumpPath 當我們沒法為-Xmx(最大堆記憶體)設定一個合適的大小,那麼就有可能面臨記憶體溢位(OutOfMemoryError)的風險,這可能是我們使用JVM時面臨的最可怕的猛獸之一導致記憶體溢位的根本原因需要仔細的定位。通常來說,分析堆記憶體快照(Heap Dump)是一個很好的定位手段,如果發生記憶體溢位時沒有生成記憶體快照,特別是對於那種JVM已經崩潰或者錯誤只出現在順利運行了數小時甚至數天的生產系統上時,將很難去分析崩潰問題。
幸運的是,我們可以通過設定 -XX:+HeapDumpOnOutOfMemoryError 讓JVM在發生記憶體溢位時自動的生成堆記憶體快照。有了這個引數,當我們不得不面對記憶體溢位異常的時候會節約大量的時間。預設情況下,堆記憶體快照會儲存在JVM的啟動目錄下名為java_pid.hprof 的檔案裡(在這裡就是JVM程序的程序號)。也可以通過設定-XX:HeapDumpPath=來改變預設的堆記憶體快照生成路徑,可以是相對或者絕對路徑。
JVM除錯工具
jps (JVM Process Status Tool)
--- 輸出jvm執行的java程序狀態資訊
命令格式:
jps [options] [hostId]
hostId預設值為當前主機 命令指令包括:
-q 不輸出類名、Jar名和傳入main方法的引數 -m 輸出傳入main方法的引數 -l 輸出main類或Jar的全限名 -v 輸出傳入JVM的引數
使用如下:
[root@localhost ~]# [root@localhost ~]# jps -m -l 28353 uyun.bat.monitor.impl.Startup 22852 uyun.bat.datastore.Startup 25799 uyun.bat.event.impl.Startup 19976 /opt/uyun/platform/jetty/start.jar 29320 uyun.bat.report.Startup
jstack
--- 輸出具體java程序內執行緒堆疊資訊
jstask應該是比較常用的JVM除錯工具,命令格式:
jstack [option] [pid]
命令指令:
-l long listings 列印執行緒鎖資訊,發生死鎖時可以使用該引數除錯 -m mixed mode 不僅輸出java堆疊資訊,還會輸出C/C++堆疊資訊
實際應用例子: 檢視程序最佔CPU的執行緒堆疊資訊
- ps -ef | grep 查詢對應程序,或者top命令檢視系統使用資訊,找出消耗最大的程序,我這裡使用的是top命令:
top - 07:38:01 up 3 days, 6:20, 5 users, load average: 15.72, 15.02, 14.14 Tasks: 148 total, 7 running, 141 sleeping, 0 stopped, 0 zombie %Cpu(s): 71.2 us, 26.1 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 2.7 si, 0.0 st KiB Mem: 20397888 total, 20124388 used, 273500 free, 0 buffers KiB Swap: 1081340 total, 1081340 used, 0 free. 2163376 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 24152 es 20 0 3323892 492160 28496 S 35.7 2.4 1613:51 java 3247 mysql 20 0 1152924 297932 5836 S 9.9 1.5 418:51.47 mysqld 20009 root 20 0 3688420 1.563g 13132 S 7.9 8.0 653:51.83 java 22852 root 20 0 3450392 546480 12828 S 7.6 2.7 322:33.85 java 5779 root 20 0 3652656 1.114g 4976 S 4.3 5.7 109:57.89 java 28353 root 20 0 3624988 337680 12824 S 3.3 1.7 125:49.11 java 268 root 0 -20 0 0 0 S 2.3 0.0 43:33.35 kworker/0:1H 11539 root 20 0 369916 14108 4020 R 2.0 0.1 0:00.06 python 25799 root 20 0 3356336 475416 12832 S 1.7 2.3 64:56.00 java 1544 root 20 0 247448 27916 1144 S 1.3 0.1 56:24.67 redis-server 11540 root 20 0 131528 5048 3880 S 1.3 0.0 0:00.04 sshd 21497 root 20 0 3306144 313020 12712 S 1.0 1.5 20:59.73 java 1 root 20 0 133816 6772 2084 S 0.7 0.0 40:38.49 systemd
經過top命令查詢,最佔用CPU的是一個Java程序,程序id為24152,佔用記憶體達到35.7%,經過ps -ef|grep pid檢視,這個程序是ElasticSearch程序
2.第二步我們需要查詢該程序內最耗費CPU的執行緒,可以使用ps -Lfp pid, ps -mp pid -o THREAD, top -Hp pid,這裡我們用第三個命令,top -Hp 24152
top - 07:44:20 up 3 days, 6:27, 5 users, load average: 19.72, 15.50, 14.42 Threads: 40 total, 1 running, 39 sleeping, 0 stopped, 0 zombie %Cpu(s): 64.3 us, 32.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 3.7 si, 0.0 st KiB Mem: 20397888 total, 19894260 used, 503628 free, 0 buffers KiB Swap: 1081340 total, 1081340 used, 0 free. 1994824 cached Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 24937 es 20 0 3319268 485312 21512 R 23.0 2.4 748:12.71 java 24953 es 20 0 3319268 485312 21512 S 4.3 2.4 151:27.67 java 24157 es 20 0 3319268 485312 21512 S 3.0 2.4 142:46.82 java 24459 es 20 0 3319268 485312 21512 S 0.3 2.4 1:58.92 java 24876 es 20 0 3319268 485312 21512 S 0.3 2.4 16:58.66 java 24152 es 20 0 3319268 485312 21512 S 0.0 2.4 0:00.00 java 24154 es 20 0 3319268 485312 21512 S 0.0 2.4 0:02.02 java 24155 es 20 0 3319268 485312 21512 S 0.0 2.4 0:00.00 java 24156 es 20 0 3319268 485312 21512 S 0.0 2.4 42:25.76 java 24158 es 20 0 3319268 485312 21512 S 0.0 2.4 0:31.47 java
這裡我們看到最耗費效能的執行緒pid為24937
- 第三步先獲取執行緒id 24937的十六進位制值
[root@localhost ~]# printf "%x\n" 24937 6169
接著使用jstack來輸出執行緒id 24937的堆疊資訊,根據執行緒id的十六進位制值grep
jstack 24152 | grep 6169
執行jstack命令後系統並沒有返回jvm資訊,而是給出一個報錯資訊:
Unable to open socket file: target process not responding or HotSpot VM not loaded
之所以會報這個找不到檔案的錯誤,首先我們得知道jvm執行時會生成一個hsperfdata_$user的目錄,Linux下預設是在/tmp,我們也可以通過配置jvm啟動引數-Djava.io.tmpdir來指定程序號資訊臨時檔案的存放位置,檢查過之後確認 /tmp下有生成目錄hsperfdata_es
[root@localhost hsperfdata_es]# pwd /tmp/hsperfdata_es [root@localhost hsperfdata_es]# ls 24152 [root@localhost hsperfdata_es]#
那之所以jstack會報錯找不到檔案,原因是ElasticSearch程序是使用es使用者啟動的,而我們登入的是root賬號,因此訪問不到這個檔案,切換使用者為es後再次使用jstack列印執行緒堆疊資訊:
[root@localhost hsperfdata_es]# su es [es@localhost hsperfdata_es]$ jstack 24152 | grep 6169 "elasticsearch[Grenade][bulk][T#1]" #49 daemon prio=5 os_prio=0 tid=0x00007f78440b2000 nid=0x6169 runnable [0x00007f7840fa1000] [es@localhost hsperfdata_es]$
打印出該執行緒資訊,顯示該執行緒是runnable正常執行的就緒狀態,經檢視詳細堆疊資訊,應該是es內部建立分片索引的程序,因此佔用比較多效能,在對自己環境程序正式排查的時候,可以多進行幾次列印,對比多次之間的執行緒執行情況,正常情況下由於程式執行速度是非常快的,如果發現多次列印對於執行緒都一直處於同一狀態如Runnable,而且堆疊資訊也卡在相同的幾處地方,就可以考慮看一下對應程式碼是不是存在死迴圈或者方法呼叫緩慢的問題了。
jmap jhat
--- jmap 輸出堆記憶體使用情況--- jhat java堆記憶體分析工具
jmap和jhat經常在一起被使用。
jmap -heap pid
用於檢視程序堆記憶體使用情況,包括堆配置引數和各代中堆記憶體使用情況,如:
whale.server01:/root# jmap -heap 17047 Attaching to process ID 17047, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.77-b03 using thread-local object allocation. Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio = 0 MaxHeapFreeRatio = 100 MaxHeapSize = 1073741824 (1024.0MB) NewSize = 175112192 (167.0MB) MaxNewSize = 357564416 (341.0MB) OldSize = 351272960 (335.0MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 21807104 (20.796875MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 134217728 (128.0MB) G1HeapRegionSize = 0 (0.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 70254592 (67.0MB) used = 22570248 (21.52466583251953MB) free = 47684344 (45.47533416748047MB) 32.126366914208255% used From Space: capacity = 9961472 (9.5MB) used = 6859688 (6.541908264160156MB) free = 3101784 (2.9580917358398438MB) 68.86219225431743% used To Space: capacity = 10485760 (10.0MB) used = 0 (0.0MB) free = 10485760 (10.0MB) 0.0% used PS Old Generation capacity = 184025088 (175.5MB) used = 99082056 (94.49201202392578MB) free = 84943032 (81.00798797607422MB) 53.841602292835205% used 24334 interned Strings occupying 2508568 bytes.
使用jmap -histo[:live] pid檢視堆記憶體中的物件數目、大小統計直方圖,如果帶上live則只統計活物件,如下:
whale.server01:/root# jmap -histo:live 17047 | more num #instances #bytes class name ---------------------------------------------- 1: 77521 8038136 [C 2: 1056 2890752 [J 3: 6362 2595656 [B 4: 5812 1968312 [I 5: 76614 1838736 java.lang.String 6: 19709 1734392 java.lang.reflect.Method 7: 18318 1268024 [Ljava.lang.Object; 8: 10179 1136280 java.lang.Class 9: 33025 1056800 java.util.concurrent.ConcurrentHashMap$Node 10: 12388 594624 org.aspectj.weaver.reflect.ShadowMatchImpl 11: 16901 540832 java.util.HashMap$Node 12: 12304 492160 java.util.LinkedHashMap$Entry 13: 12388 396416 org.aspectj.weaver.patterns.ExposedState 14: 2633 352464 [Ljava.util.HashMap$Node; 15: 11008 352256 java.util.Hashtable$Entry 16: 436 330440 [Ljava.util.concurrent.ConcurrentHashMap$Node; 17: 13383 321192 java.util.ArrayList 18: 9319 298208 java.lang.ref.WeakReference 19: 741 278616 java.lang.Thread 20: 17352 277632 java.lang.Object 21: 5707 228280 java.lang.ref.SoftReference 22: 3612 173376 java.util.HashMap 23: 302 164288 rx.internal.util.unsafe.SpscArrayQueue 24: 5104 163328 java.util.concurrent.locks.ReentrantLock$NonfairSync 25: 2872 160832 java.util.LinkedHashMap 26: 4784 153088 java.lang.ThreadLocal$ThreadLocalMap$Entry 27: 1828 146240 java.lang.reflect.Constructor 28: 1473 139856 [Ljava.lang.ThreadLocal$ThreadLocalMap$Entry; 29: 5152 123648 java.beans.MethodRef 30: 3831 119752 [Z 31: 5550 118632 [Ljava.lang.Class; 32: 2003 112168 java.security.Provider$Service 33: 464 107616 [Ljava.util.Hashtable$Entry;
參考文獻: 傳送門 傳送門2(JVM效能調優監控工具jps、jstack、jmap、jhat、jstat使用詳解)傳送門3(jstat命令使用)