java web服務器cpu佔用太高的處理

平時項目中有時遇到cpu太高的狀況,在此基於本身有限的經驗寫個分享,此處的服務器都是基於linux平臺。html

cpu的佔有線程類型總的來講分爲兩種:
us :用戶空間佔用CPU百分比
sy :內核空間佔用CPU百分比
在linux下能夠經過top命令查看詳細,示例以下:linux

 

通常來說CPU us高的解決方法:
CPU us 高的緣由主要是執行線程不須要任何掛起動做,且一直執行,致使CPU 沒有機會去調度執行其餘的線程。
CPU sy高的解決方法:
CPU sy 高的緣由主要是線程的運行狀態要常常切換,對於這種狀況,常見的一種優化方法是減小線程數數據庫

 

我平時具體的步驟以下:緩存

1.獲得線程最高的幾個id(ps- process state)服務器

ps  -eLo pid,lwp,pcpu | grep  15285|sort -nk 3   網絡

 

2.導出JAVA線程棧信息異步

命令:kill -3 [PID] 或者 jstackjvm

 

3.從棧信息中找到線程數多的幾個socket

命令:sort  文件名 | uniq -c | sort -nk 1優化

 

4.分別分析線程數最多的前十個線程和線程佔用cpu最高的前10個線程

      這步是最關鍵的,找出這些異常點,好比某個業務功能點佔用較高的cpu或者某種類型的線程數量比較多,這個和業務以及具體程序緊密關聯的,在此就很少說了。

 

5.分析佔用cpu最高的前10個線程,結果示例以下:

0x1a5:gc線程
" Concurrent Mark-Sweep GC Thread#0" prio=1 tid=0x0000002b29df1400 nid= 0x1a5 runnable 
0x35f:memcache線程
"memcache5-CacheThread" prio=1 tid=0x0000002b3d277de0 nid= 0x35f runnable [0x0000000042755000..0x0000000042755c30]
0x35e:memcache線程
"memcache1-CacheThread" prio=1 tid=0x0000002b371212f0 nid=0x35e runnable [0x0000000042654000..0x0000000042654cb0]
0x14e9:RMI線程
" RMI TCP Connection(102)-10.23.241.59" daemon prio=1 tid=0x0000002b37e72790 nid=0x14e9 runnable [0x000000005103c000..0x000000005103deb0]
0x1be:memcache線程
"memcache5-CacheThread" prio=1 tid=0x0000002b3dba4790 nid=0x1be runnable [0x0000000041a48000..0x0000000041a48eb0]
0x1bd:memcache線程
" memcache1-CacheThread" prio=1 tid=0x0000002b3fb70340 nid=0x1bd runnable [0x0000000041947000..0x0000000041947b30]
0x1af:jdk編譯線程
"CompilerThread1" daemon prio=1 tid=0x0000002b30e11620 nid=0x1af waiting on condition [0x0000000000000000..0x000000004123f7c0]
0x1ae:jdk編譯線程
"CompilerThread0" daemon prio=1 tid=0x0000002b30e10280 nid=0x1ae waiting on condition [0x0000000000000000..0x000000004113e440]
0x1684:http請求線程,經過該線程棧能夠看到此處調用的是hibernate查詢
" http-8080-Processor123" daemon prio=1 tid=0x0000002b37dfd9d0 nid=0x1684 runnable [0x000000005afd7000..0x000000005afdcd30]
 
--------------------------------------------------------------------------------------------------------------------------------

 6.系統優化

      若是找出了哪些功能點佔用cpu高,接下來就須要優化了,能夠從業務和技術手段兩方面來進行,平時工做中比較經常使用的技術手段:

      彈性時間:對高使用率的請求分散到不一樣的時間,好比採用隊列或異步,減小同一時間處理的請求

      批處理或定時任務:把請求組合成批,這樣可使得時間真真的都有效的用在了處理上,而不是網絡傳輸等準備工做上。(減小網絡傳輸、數據庫鏈接、socket鏈接)

      緩存:結果緩存起來,空間換時間

  --------------------------------------------------------------------------------------------------------------------------------

 

7.若是是gc線程比較費時,則須要進一步的定位:

      首先查看一下gc策略是否合理,而後用命令jmap -F -dump:live,file=jmap.hprof [PID] 導出內存dump文件,我通常每隔5s導一次,一共導出3次。用Eclipse Memory Analyzer分析導出來的文件,分析是哪一個類佔用內存比較多,分析出可能存在內存泄露的地方。

      注意jvm分配內存時一個大對象的分配比多個小對象的分配效率要低,若是對象比較大,進行拆分能提升效率,具體緣由以下:

      Java對象所佔用的內存主要從堆上進行分配,堆是全部線程共享的,所以在堆上分配內存時須要進行加鎖,這致使了建立對象開銷比較大。當堆上空間不足時,會觸發GC,若是GC後空間仍然不足,則拋出OutOfMemory錯誤信息。Sun JDK爲了提高內存分配的效率,會爲每一個新建立的線程在新生代的Eden Space上分配一塊獨立的空間,這塊空間稱爲TLAB(Thread Local Allocation Buffer),其大小由JVM根據運行狀況計算而得,可經過-XX:TLABWasteTargetPercent來設置TLAB可佔用的Eden Space的百分比,默認值爲1%。JVM將根據這個比率、線程數量及線程是否頻繁分配對象來給每一個線程分配合適大小的TLAB空間 。在TLAB上分配內存時不須要加鎖,所以JVM在給線程中的對象分配內存時會盡可能在TLAB上分配,若是對象過大或TLAB空間已用完,則仍然在堆上進行分配,所以在編寫Java程序時,一般多個小的對象比大的對象分配起來更加高效

 

http://hi.baidu.com/i1see1you/blog/item/6438aecac4dd959bc917683d.html

相關文章
相關標籤/搜索