jvm性能優化小入門

緣起

我司項目如今的java項目都是基於springboot開發,經過Jenkins與ansible直接把項目編譯的jar在阿里雲主機上部署運行,幾臺雲主機的配置大都是通用型2核8G,java項目不免遇到諸如內存溢出這類錯誤,爲了讓程序在服務器上有最佳運行效果,須要對每一個項目進行jvm調優,JDK自己提供了不少方便的JVM性能調優監控工具,除了集成式的VisualVM和jConsole外,還有jps、jstack、jmap、jhat、jstat等小巧的工具,本文但願能起拋磚引玉之用,讓你們能開始對JVM性能調優的經常使用工具備所瞭解java

  1. jps:查看全部java項目進程 
    通常我都用: jps -m -l PID 這樣會列出 
    21996 /usr/local/platform/patient/bin/patient.jar –spring.profiles.active=test 
    21996 是進程id 
    /usr/local/platform/patient/bin/patient.jar 是詳細的進程名稱 
    –spring.profiles.active=test 是傳入main類或者jar包的參數c++

  2. jstack :查看某個java進程內的堆棧信息,根據堆棧信息,咱們能夠定位到具體代碼,在jvm性能調優中使用的特別多! 
    我通常這麼用: jstack -m -l PID 
    其中 -m 參數不只會列出java對戰信息,還會列出系統級別native方法的c/c++堆棧信息 
    -l 會打印出額外的鎖信息spring

    栗子:咱們找我patient這個java進程最消耗CPU的線程springboot

  • 首先用jps獲取patient這個java進程的ID 
    21996 /usr/local/platform/patient/bin/patient.jar –spring.profiles.active=test服務器

  • 獲得進程ID爲21996,第二步找出該進程內最耗費CPU的線程,能夠用top -Hp 21996 獲得以下:網絡

Threads:  32 total,   0 running,  32 sleeping,   0 stopped,   0 zombie%Cpu(s):  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 stKiB Mem :  1867248 total,    94444 free,  1592828 used,   179976 buff/cacheKiB Swap:  2097148 total,  2064196 free,    32952 used.    73720 avail MemPID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND 21996 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 21999 root      20   0 2564180 241912   7580 S  0.0 13.0   0:05.11 java 22000 root      20   0 2564180 241912   7580 S  0.0 13.0   0:16.09 java 22001 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22002 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.01 java 22003 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22004 root      20   0 2564180 241912   7580 S  0.0 13.0   0:15.24 java 22005 root      20   0 2564180 241912   7580 S  0.0 13.0   0:06.93 java 22006 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22007 root      20   0 2564180 241912   7580 S  0.0 13.0   5:06.79 java 22081 root      20   0 2564180 241912   7580 S  0.0 13.0   0:01.29 java 22082 root      20   0 2564180 241912   7580 S  0.0 13.0   0:01.67 java 22101 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.43 java 22121 root      20   0 2564180 241912   7580 S  0.0 13.0   0:11.48 java 22123 root      20   0 2564180 241912   7580 S  0.0 13.0   0:01.42 java 22149 root      20   0 2564180 241912   7580 S  0.0 13.0   0:13.73 java 22150 root      20   0 2564180 241912   7580 S  0.0 13.0   0:17.81 java 22232 root      20   0 2564180 241912   7580 S  0.0 13.0   0:08.78 java 22233 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.10 java 22234 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.03 java 22235 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22236 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22237 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22238 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22239 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22240 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22241 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22242 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java 22243 root      20   0 2564180 241912   7580 S  0.0 13.0   0:07.24 java 22244 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.02 java 22245 root      20   0 2564180 241912   7580 S  0.0 13.0   0:14.57 java 36964 root      20   0 2564180 241912   7580 S  0.0 13.0   0:00.00 java

其中TIME+這一列是指耗時時間,這一列裏面22007 最耗時,咱們在命令行裏用printf 「%x\n」 22007 獲得16進制55f7併發

  • 這時候用jstack 21996 55f7 來輸出堆棧信息以下: 
    「VM Periodic Task Thread」 os_prio=0 tid=0x00007ff3980f0800 nid=0x55f7 waiting on condition 
    通過發現這個堆棧信息顯示的線程狀態是waiting on condition,意思是正在等待網絡讀寫,這多是一個網絡瓶頸徵兆。 
    若是這裏列出來的是一個java類名,則就能夠找到項目裏的類,結合堆棧信息,進行性能改進app

  1. jmap: 通常結合jhat用來查看堆棧內存使用狀況, 
    jmap -heap 21996 顯示堆內存以下:jvm

Attaching to process ID 21996, please waitDebugger attached successfully.Server compiler detected.JVM version is 25.141-b16using thread-local object allocation.Mark Sweep Compact GCHeap Configuration:MinHeapFreeRatio         = 40MaxHeapFreeRatio         = 70MaxHeapSize              = 478150656 (456.0MB)NewSize                  = 10485760 (10.0MB)MaxNewSize               = 159383552 (152.0MB)OldSize                  = 20971520 (20.0MB)NewRatio                 = 2SurvivorRatio            = 8MetaspaceSize            = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize         = 17592186044415 MBG1HeapRegionSize         = 0 (0.0MB)

這裏咱們能夠看到咱們堆內存各個區的內存大小。注意:這個是jdk1.8的,其中MetaspaceSize代替了PermGenide

優化

上面介紹了用jvm的工具查看java進程,並查找相應堆棧信息,根據堆棧信息優化程序,也列出了堆棧內存的大小信息,要避免內存溢出,在程序在承受較大訪問量的時候,程序仍然能夠健康運行,就要根據本身機器狀況,多作幾回抗壓試驗,找出性能最好的參數設置 
首先jdk8 運行時一般包含 計數器,棧,堆,本地方法棧,方法區,堆。每一個部分的優化參數名稱以下:

Xss:每一個線程的棧內存大小Xmx:JAVA HEAP的最大值、默認爲物理內存的1/4Xms:JAVA HEAP的初始值,server端最好Xms與Xmx同樣Xmn:JAVA HEAP young區的大小XX:PermSize:設定內存的永久保存區域XX:MaxPermSize:設定最大內存的永久保存區域

我基於jdk1.8 作了一個優化參數,我司單臺服務器的配置(2核8G),單臺服務器我部署2臺服務,配置以下(主要是堆棧)

exec java \-Dfile.encoding=UTF-8 \-Xss1024K//棧內存1m-Xms1024m//堆內存最小1g-Xmx2048m//堆內存最大2g-Xmn256m //yong-XX:MaxMetaspaceSize=512m //方法區512m###常規項目優化-XX:+DisableExplicitGC //忽略手動調用GC, System.gc()的調用就會變成一個空調用,徹底不觸發GC-XX:+UseConcMarkSweepGC //併發標記清除(CMS)收集器-XX:+CMSParallelRemarkEnabled //下降標記停頓-XX:LargePageSizeInBytes=128m //內存頁的大小-XX:+UseFastAccessorMethods //原始類型的快速優化-XX:+UseCMSInitiatingOccupancyOnly //使用手動定義初始化定義開始CMS收集-XX:CMSInitiatingOccupancyFraction=70 //使用cms做爲垃圾回收使用70%後開始CMS收集-Duser.timezone=GMT+8 //避免CentOS坑爹的時區設置-XX:+UseG1GC \-XX:MaxGCPauseMillis=100 \-XX:InitiatingHeapOccupancyPercent=35 \######gc信息打印-verbose:gc \-XX:+PrintGCDetails \-XX:+PrintGCDateStamps \-XX:+PrintGCTimeStamps \-XX:+PrintGCApplicationStoppedTime \-Xloggc:${BASE_DIR}/logs/jvm_gc.log \-XX:ErrorFile=${BASE_DIR}/logs/jvm_err.log \-XX:+HeapDumpOnOutOfMemoryError \-XX:HeapDumpPath=${BASE_DIR}/logs/jvm_dump_pid%p.hprof \-jar /usr/local/platform/patient/bin/patient.jar --spring.profiles.active=prod

各位項目仍是要根據本身公司服務器配置狀況來進行相應優化測試

相關文章
相關標籤/搜索