生產環境下JVM調優
最小堆、最大堆內存設為1G,使用G1垃圾回收器,最長的GC暫停時間設為200毫秒,如果時間過長,會相應調整空間的大小(單位是毫秒),新生代最小比例20%,最大比例30%,
+DisableExplicitGC關閉系統調用GC功能 【System.gc() 默認會觸發一次Full Gc】
打印GC及GC詳細信息、GC時間戳,在out of memory的情況下的內存dump輸出到指定路徑,GC日志路徑
nohup java -jar -server -Xms1G -Xmx1G -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+UnlockExperimentalVMOptions -XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=30 -XX:+DisableExplicitGC -XX:+PrintGC
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/www/$project_name/online/logs/oom-error_8000.log Xloggc:/data/www/$project_name/online/logs/gc_log_8000.log ***.jar > ***.log &
- 另一種GC日志輸出
設置GC日志的路徑,%t 會記錄當前日期,+UseGCLogFileRotation開啟滾動日志,
NumberOfGCLogFiles設置文件數量5個,GCLogFileSize文件大小20M (超過20M,進入下一個文件)
-Xloggc:/opt/xxx/logs/xxx-xxx-gc-%t.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCCause
JVM調優思路
-
- 常規JVM調優:當 Java 線上出現問題,如 CPU 飆升、負載突高、內存溢出等問題,需要查命令,查網絡,然后 top、jps、jstat、jstack、jmap、jhat、hprof 等操作。
- 對於OOM Erro dump轉儲文件、GC日志進行分析,解決問題
-
- 使用 Arthas 輕松定位,圖形化界面、迅速解決,及時止損。
- https://blog.csdn.net/u013735734/article/details/102930307
- 監控: arthas / jconsole / jvisualVM / Jprofiler(最好用)
-
- 線上查找 ( cmdline || arthas )
- jstat -gc 動態觀察gc情況 stat -gc 4655 500 : 每個500個毫秒打印GC的情況
查看運行的 java 進程信息 (top、jps )
$ jps -mlvV
$ jps -mlvV | grep [xxx]
top 、 top -Hp pid
top 查看所有進程的 CPU、內存狀態
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7945 root 20 0 2813304 301908 14000 S 101.3 30.3 20:44.36 javatop -Hp pid 查看指定進程下所有線程的 CPU、內存狀態
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
7947 root 20 0 2813304 309196 14064 S 93.7 31.0 28:16.02 java
查看GC匯總信息 ( jstat )
- jstat -gcutil 進程ID
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 99.33 86.40 97.12 94.49 21 2.968 5 1.027 3.996S0 ---> 年輕代中第一個survivor(幸存區)已使用的占當前容量百分比
S1 ---> 年輕代中第二個survivor(幸存區)已使用的占當前容量百分比
E ---> 年輕代中Eden(伊甸園)已使用的占當前容量百分比O ---> old代已使用的占當前容量百分比
M ---> 元數據空間使用比例
CCS ---> 壓縮使用比例YGC ---> 從應用程序啟動到采樣時年輕代中gc次數
YGCT ---> 從應用程序啟動到采樣時年輕代中gc所用時間(s)
FGC ---> 從應用程序啟動到采樣時old代(全gc)gc次數
FGCT ---> 從應用程序啟動到采樣時old代(全gc)gc所用時間(s)
GCT ---> 從應用程序啟動到采樣時gc用的總時間(s)
- jstat -gc 動態觀察gc情況 stat -gc 4655 500 : 每個500個毫秒打印GC的情況
進程、線程信息並進行分析 (jinfo 、jstack、jmap 、jhat )
-
jinfo pid
進程和線程的 具體信息
-
jstack
jstack 定位線程、進程狀況
-
jmap -histo 4655 | head -20
查找有多少對象產生
-
jmap -dump:live,format=b,file=heap.bin pid
生成dump轉儲文件,線上系統,內存特別大,jmap執行期間會對進程產生很大影響,甚至卡頓(電商不適合)
-
使用MAT / jhat /jvisualvm 進行dump文件分析
https://www.cnblogs.com/baihuitestsoftware/articles/6406271.html -
jhat -J-mx512M xxx.dump
http://192.168.17.11:7000
分析日志
dump 文件里,值得關注的線程狀態有:
-
死鎖,Deadlock(重點關注)
-
執行中,Runnable
-
等待資源,Waiting on condition(重點關注)
-
等待獲取監視器,Waiting on monitor entry(重點關注)
-
暫停,Suspended
-
對象等待中,Object.wait() 或 TIMED_WAITING
-
阻塞,Blocked(重點關注)
-
停止,Parked
tid指Java Thread id。nid指native線程的id。prio是線程優先級。
[0x00007f1d2c4be000] 是線程棧起始地址。
Thread.State:WAITING (parking) 等待,線程掛起中。
parking to wait for <0x00000000f5dee038>
本線程肯定是在等待某個條件的發生,來把自己喚醒。其次,SynchronousQueue 並不是一個隊列,只是線程之間移交信息的機制,當我們把一個元素放入到 SynchronousQueue 中時必須有另一個線程正在等待接受移交的任務,因此這就是本線程在等待的條件。
dump文件實例分析
https://www.cnblogs.com/zhengyun_ustc/archive/2013/01/06/dumpanalysis.html
"pool-1-thread-34" #41 prio=5 os_prio=0 tid=0x00007f1d501a2000 nid=0x2001 waiting on condition [0x00007f1d2c4be000]
java.lang.Thread.State: WAITING (parking)
? at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000f5dee038>
(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:1074)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
JVM常用參數詳解
- nohup java -jar -server
設置為服務端模式, 吞吐量優先 -client
- nohup java -jar project.jar >> log.out 2>&1 &
錯誤輸出和標准輸出,追加到log.out
- nohup java -jar Project.jar >/dev/null 2>log &
標准輸出至/dev/null ( 空洞 ),只輸出錯誤信息至log
nohup 不中斷運行,與用戶終端無關
>> 輸出重定向
2>&1 (2)標准錯誤輸出 (>) 重定向到 (&1)標准輸出
2>&1 標准錯誤輸出重定向到標准輸出
& 標識進程為后台進程
-
-Xms$max_memory -Xmx$max_memory
指定Xms最小堆,Xmx最大堆的大小,避免每次垃圾回收完成后JVM重新分配內存.
-
-XX:+UseG1GC
G1垃圾回收器
-
-XX:MaxGCPauseMillis=200
最長的GC暫停時間,如果時間過長,會相應調整空間的大小(單位是毫秒)
-
-XX:+UnlockExperimentalVMOptions
有些時候當設置一個特定的JVM參數時,JVM會在輸出“Unrecognized VM option”后終止。如果發生了這種情況,你應該首先檢查你是否輸錯了參數。然而,如果參數輸入是正確的,並且JVM並不識別,或許需要設置-XX:+UnlockExperimentalVMOptions 來解鎖參數
-
-XX:G1NewSizePercent=20 -XX:G1MaxNewSizePercent=30
新生代最小比例20%,最大比例30%
-
-XX:+DisableExplicitGC
關閉系統調用GC功能 System.gc() 默認會觸發一次Full Gc
-
-XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps
打印GC、GC詳細信息、GC時間戳
-
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/www/$project_name/online/logs/oom-error_8000.log當出現OOM內存溢出時進行堆轉儲,並指定具體路徑
-
-Xloggc:/data/www/$project_name/online/logs/gc_log_8000.log
指定GC日志路徑