使用tomcat做為java容器,cpu佔用偏高的原因,目前公司伺服器上面跑的ubuntu環境nginx+tomcat+mysql運行一段時間之後java進程cpu偏高,會出現網站打不開的情況。所以進行了如下分析。
一,首先查看tomcat日誌,如果有出現OOM錯誤(記憶體溢出)可以對應的加大jvm的記憶體大小。
1,修改tomcat目錄下bin目錄下的catalina.sh檔案,在
#JAVA_OPTS="$JAVA_OPTS -Dorg.apache.catalina.security.SecurityListener.UMASK=`umask`"
這行下面添加如下內容
JAVA_OPTS="-server -Xms2048m -Xmx2048m -Xmn512m -XX:PermSize=256M -XX:MaxPermSize=256m -Xss256k -XX:SurvivorRatio=4 -XX:MaxTenuringThreshold=20 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=73 -XX:+UseCMSCompactAtFullCollection -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=2 -Djava.awt.headless=true"
上面的配置是基於4G記憶體設定的,具體修改看自己手上伺服器的配置。
參數的含義:
-server 告訴tomcat使用server模式 能獲得更大並發數和效能
-Xms2048m -Xmx2048m JVM記憶體的總數
-Xmn512m 年輕代記憶體大小
-XX:PermSize=256M -XX:MaxPermSize=256m 永久帶記憶體大小
Xss256k 線程大小
-XX:SurvivorRatio=4 設定年輕代中Eden區與Survivor區的大小比值。設定為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6
-XX:MaxTenuringThreshold=20 設定垃圾最大年齡。如果設定為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設定為一個較大值,則年輕代對象會在Survivor區進行多次複製,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的機率
-XX:+UseParNewGC 對年輕代採用多線程並行回收,這樣收得快
XX:+UseConcMarkSweepGC
CMS gc,這一特性只有jdk1.5即後續版本才具有的功能,它使用的是gc估算觸發和heap佔用觸發。
我們知道頻頻繁的GC會造面JVM的大起大落從而影響到系統的效率,因此使用了CMS GC後可以在GC次數增多的情況下,每次GC的回應時間卻很短,比如說使用了CMS GC後經過jprofiler的觀察,GC被觸發次數非常多,而每次GC耗時僅為幾毫秒
-XX:CMSInitiatingOccupancyFraction=73 說明年老代到73%滿的時候開始執行對年老代的並發記憶體回收(CMS)。
-XX:+UseCMSCompactAtFullCollection 開啟對年老代的壓縮。可能會影響效能,但是可以消除片段
-XX:+CMSParallelRemarkEnabled 降低標記停頓
-XX:CMSFullGCsBeforeCompaction 由於並發收集器不對記憶體空間進行壓縮、整理,所以運行一段時間以後會產生“片段”,使得運行效率降低。此值設定運行多少次GC以後對記憶體空間進行壓縮、整理。
參考網站:http://blog.csdn.net/lifetragedy/article/details/7708724
2,修改參數之後重啟tomcat,查看參數是否生效
jmap -heap javaPID 查看JVM記憶體配置情況
jstat -gcutil javaPID 1000 30 查看JVM記憶體回收情況
經過上面的修改應該就可以完成對tomcat進程飆高的情況了。如果運行一段時間之後通過jstat查看各個記憶體代的使用方式,發現老年代100% 一直在觸發FULL GC 那就是記憶體大小的原因了。有條件的可以添加記憶體,沒條件的可以設定 每天重啟一次tomcat或者一個星期重啟一次來釋放jvm記憶體。問題解決。
二,如果想查看是否是代碼層的原因,就需要另外的辦法
1,使用命令jstack命令查看佔用CPU最高的線程。
PID=`ps aux | grep java | head -1 | awk '{print $2}'`
ps -mp $PID -o THREAD,tid,time | sort -k 2 -r | head -20
echo -n -e " shur ru:"
read f
if [ -z $f ]
then
echo "no"
else
jstack "$PID" | grep `printf "%x\n" $f` -A 30
fi
一個簡單的監控指令碼,查看JAVA進程佔用CPU最高的線程在做什麼以此來分析是否是代碼層的問題。
參考網站:http://blog.csdn.net/blade2001/article/details/9065985