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