有時候好好的程序放到生產服務器上一段時間後,就會發現服務器響應緩慢,進而進一步發現是cpu太高,因而就慌了,形成cpu太高的緣由不少,不過大可能是因爲資源吃緊形成,例如:sql執行過慢,程序裏存在死循環,數據庫鏈接未釋放,網絡阻塞致使的第三方框架代碼出現死循環,大量的操做致使死鎖等html
public class CpuTest { public static void main(String[] args) throws InterruptedException { loop(); endlessLoop(); } public static void endlessLoop() throws InterruptedException { while (true) { System.out.println("hello world! loop!"); } } public static void loop(){ for (int i = 0; i < 10000; i++) { System.out.println("hello world! endless loop!"); } } }
分析點擊抽樣器->CPU->查看CPU樣例,發現endlessLoop()方法最耗CPU(這裏有2個方法 loop和endlessLoop)
java
查看線程cpu耗時,發現main線程最耗時,點擊增量,能夠今後刻觀察,cpu耗時的增加速率
node
查看線程dump,主要觀察main線程,發現main線程當前狀態下一直在執行CpuTest.endlessLoop(CpuTest.java:14)
,這裏能夠定位問題位置,同時細心的童鞋能夠觀察看後面執行System.out.println("");方法是要先加鎖的。
linux
截圖一段,我生產服務器(tomcat+springmvc)main線程的狀況,其實只想說明web項目啓動的main方法在中間件裏。
web
VisualVm只能定位JVM的cpu狀況,可是生產主機上不光是Java程序,這時咱們要採起另外的方案。算法
1.看監控數據是否正常,cpu,mem。spring
CPU佔用1.5左右(100-98.0id) 內存佔用50%(435/100*100%=43.5%) 阿里雲監控內存大小轉成實際佔用內存大小,相似windows ,平均負載 0.1 差很少,其餘幾個參數,這裏暫不介紹。sql
2.假設異常,找到異常的PID。數據庫
這裏推薦htop
(清晰進程,線程,命令行,排序支持鼠標雙擊,過濾,kill程序,標記某個線程或者進程,安裝apt-get install htop
)
windows
若是你沒有服務器上安裝軟件的權限的話,就老老實實用top
。經過top
命令(默認3秒刷新,回車空格手動刷新,top -d 5
5秒刷新,也能夠進入top後輸入d
設置刷新時間,top -p 4360
監控指定進程),而後按X ,默認按照CPU%排序,查看系統運行狀況,若是想強制按CPU 降序,則輸入大寫P,若是強制按內存降序,則輸入大寫M(top命令是交互式的)。
解讀:
1).如今系統時間 10:18.44 ,系統一直運行了 131天16小時51分,當前有1個用戶登陸系統(相同帳號也算不一樣用戶),平均負載分別爲0.00,0.01,0.05(分別爲1分鐘,5分鐘,15分鐘的負載狀況,load average是每隔5秒鐘檢查一次活躍的進程數,用特定的算法獲得的數值,而後除以邏輯CPU數量,若是負載持續大於cpu個數,則代表負載太高) 。大概能夠看出系統負載很低,運行狀態健康。
2).當前一共有103個進程,處於運行的有2個,處於休眠狀態的有101個,處於中止狀態的有0個,處於殭屍狀態的有0個。大概能夠看出系統進程總數較少,環境比較單純,運行中的進程很少。
3).0.3 us
用戶空間佔用CPU 0.3%,0.7 sy
內核佔用CPU 0.7%,0.0 ni
改變過優先級的進程佔用CPU的百分比,98.0 id
空閒CPU的百分比爲98.0,0.3 wa
IO等待所佔用CPU的百分比爲0.3,0.3 hi
硬中斷(Hardware IRQ)佔用CPU的百分比爲0.3(外設給CPU的異步信號(中斷),例如:網卡收到數據包),0.0 si
軟中斷佔用cpu的百分比爲0(軟件自己給操做系統內核的中斷信號,一般由硬中斷處理程序對操做系統內核的中斷),0.3 st
虛擬機被hypervisor偷去CPU的時間。
4).KiB Mem
表明內存佔用,1016272 total
內存總的大小1g(以kb爲單位),941492 used
使用中的內存總量爲0.9g,74780 free
空閒內存總量爲74m(嚇一跳吧,才74M,這個不是實際剩餘的內內存大小),115900 buffers
緩存的內存量爲115m,389836 cached
cached大小380M。空閒內存總量只有74m,若是是windows去理解的話,此臺服務器已經快掛了,實際內存大小等於74M+ buffers+cached = 580m(哈哈,夠用,才佔用一半呢), linux的內存管理和windows是不同的,Linux會借用空閒的內存看成磁盤緩存, 磁盤數據緩存會讓linux運行的更快,它永遠不會從程序中拿出內存,它沒有任何缺點,只是會混淆新手,若是你的應用程序須要更多的內存,他們會回收一部分用做磁盤數據緩存的物理內存,返回給應用程序,這個過程不須要啓動交換,磁盤緩存(Disk caching)是不能禁用的, 可是能夠釋放磁盤緩存 1).只釋放pagecache(文件緩存) echo 1 > /proc/sys/vm/drop_caches
2).釋放dentries和inodes echo 2 > /proc/sys/vm/drop_caches
3).釋放pagecache,dentries和inodes echo 3 > /proc/sys/vm/drop_caches
具體原理能夠查看linuxatemyram
咱們利用free
進一步證明上面的內容
1).shared表明被線程共享的內存大小(大多數已經捨棄掉),buffer用來給塊設備作緩存(記錄文件系統的metadata和tracking in flight pages),cache緩存文件(第二次打開就很快),linux系統cached比較大,cached大小390m,buffers爲110m。
2).435288表明 -buffers/cache (應用程序實際使用330m內存) 580984 表明 +buffers/cache(實際剩餘內存大小580m)。
3).重要等式 total = used + free
used(-buffers/cache) = used(Mem)-buffers(Mem)-cached(Mem)
free(+buffers/cache) = free(Mem) + buffers(Mem) +cached(Mem)
。
4).free
命令的值是從 /proc/meminfo 文件裏讀到的。
5).Swap 交換區 總共大小 0 kb,已經使用0kb,釋放了0Kb,若是swap used > 0,則能夠說明系統內存瓶頸了。
6).內存總和 free -t
總和等於total(Mem) + total(Swap)。
7).通常經常使用命令 free -s 3
每3秒觀察一次內存使用狀況。
佔用cpu最高的進程是java,PID爲28628,USER進程全部者root,PR優先級20,NI爲0(負值優先級高,正值優先級低,PR=NI+20) ,VIRT進程使用虛擬內存1G(java進程最高只能佔用到1G),RES進程實際使用的物理內存270M(不包含swap和shared),SHR共享內存大小5M,S進程狀態隨眠狀態(S睡眠,R運行,T中止或被跟蹤,Z殭屍,D不可中斷睡眠態),%CPU佔用CPU 0.7%,%MEM佔用內存27%,TIME+進程使用cpu的時間54分40.12秒。整體看java進程運行良好。
3.這裏假設PID爲16368的進程佔用CPU比較高(由於作了屢次實驗,因此PID沒辦法和上面的28628保持一致),
先用ps -ef | grep java
,也能夠用htop
filter java,也能夠jps -v
找到 java的進程ID 16368(只能查看當前用戶的java pid,不太建議使用,-v顯示詳細信息,也能夠不加)
?表明終端設備未知,Sl表明休眠狀態多線程
Linux經過進程查看線程的方法 1).htop
按t(顯示進程線程嵌套關係)和H(顯示線程) ,而後F4過濾進程名。2).ps -eLf | grep java
(快照,帶線程命令,e是顯示所有進程,L是顯示線程,f全格式輸出) 3).pstree -p <pid>
(顯示進程樹,不加pid顯示全部) 4).top -Hp <pid>
(實時) 5).ps -T -p <pid>
(快照) 推薦程度按數字從小到大。
4.利用jstack 16368 > 2016-1-21.tdump
(jstack是jdk自帶的生成java stack和native stack的工具) 把threaddump輸出到文件裏,這裏假設PID爲16369(通常比進程號+1的是main線程,若是存在main線程貌似最早分配)的線程佔用CPU最高,將其ID轉成16進制0x3ff1(使用命令 printf "%x\n" 16369
輸出3ff1)。
5.搜索threaddump文件,nid= 0x3ff1的線程堆棧,經過堆棧信息,就能夠定位到佔用CPU最高的代碼地方(這裏是正常的)。
好啦,CPU衝高問題排查完畢,有了這樣的知識體系,之後徹底能夠觸類旁通,coder君同時附上其餘經常使用配合命令。
jstat -gcutil 16368 1000ms
參考jstat -help
,也能夠查看遠程主機的GC狀況,須要遠程主機開啓jstatd服務。
jmap -dump:format=b,file=2016-1-21.mdump 16368
生成堆dump,放到mat或者vvm進行分析,上篇分析OOM有講到。
jinfo 16368
感謝您的耐心閱讀,若是您發現文章中有一些沒表述清楚的,或者是不對的地方,請給我留言,你的鼓勵是做者寫做最大的動力,
若是您認爲本文質量不錯,讀後以爲收穫很大,不妨小額贊助我一下,讓我更有動力繼續寫出高質量的文章。
做 者 : @mousycoder
原文出處 : http://mousycoder.com/2016/02...
創做時間:2016-2-14
更新時間:2016-2-14