生產環境下JVM調優參數


生產環境下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日志進行分析,解決問題
    • 線上查找 ( 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 java

top -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.996

S0 ---> 年輕代中第一個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日志路徑


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM