jvm 命令使用調優 經過jstat、jmap對java程序進行性能調優

轉載:http://blog.csdn.net/jerry024/article/details/8507589html

轉載: https://blog.csdn.net/zhaozheng7758/article/details/8623530java

 

經過jstat、jmap對java程序進行性能調優

第一次寫技術博客,本文記錄了我對服務器cpu佔用率100%問題的排查過程和最終結果,算是一篇學習日誌。算法

 

本人屬於學習中的菜鳥碼農,若有什麼理解上的誤差的,還請各路大神指正。apache

 

關鍵詞:

jstat , jmap, heap, GC, smartupload, 內存泄漏tomcat

 

1. 背景

硬件供應商屢次反映,在tomcat啓動一段時間後,常常出現cpu佔用率100%,且重啓前一直保持在100%的狀況。在重啓後cpu佔用率回落,可是一段時間後再次出現問題。服務器

下圖爲cpu佔用率100%時使用top命令的截圖,能夠看到java進程的cpu佔用率幾經幾乎達到了400%(服務器爲4核cpu)jvm

 

<1><1>jsp

2.問題定位

2.1問題猜想

對於cpu佔用率100%的狀況,產生如下兩種猜想:工具

a. 程序長時間佔用系統IO,致使CPU佔用率100%性能

b.程序存在嚴重內存泄露,致使jvm頻繁執行full GC,從而使cpu佔用率提升,形成服務器假死

 

2.2jvm的內存管理和垃圾回收機制

java對內存的管理主要分爲兩種:棧(stack)和堆(heap) 方法區,程序計數器等不作討論

 

stack: 在每一個線程啓動時由jvm自動分配固定大小的地址,stack內主要保存操做符,值對象(int,float等基礎數據類型),和引用對象的指針因爲stack固定大小,且主要操做爲push和pop,並不涉及到垃圾回收等問題,所以不作展開。

heap:堆在線程執行過程當中自動分配大小,大小能夠隨時改變,主要用於保存對象(Object),對象在結束生命週期結束以後便會由JVM的垃圾回收機制自動進行回收堆可分爲3大部分年輕代(Young Generation)、年老代(Old Generation)和持久代(Permanent Generation)。

年輕代:年輕代又可分爲3個小區:Eden,兩個等大的Survior區(from 和 to)。其中Eden主要存放新建的對象,當Eden區沒法再存放更多的對象時,jvm會發起年輕代GC(Minor GC),釋放Eden中的對象,Minor GC的特色是發生頻率高,執行速度也極快,對系統效率的影響並非很大。當Eden區中的對象通過一次Minor GC仍然沒有被釋放時,這部分對象將被移入Survior區(對象可能進入from區,也可能進入to區,有具體算法,此處不作展開)。當Survior區中的對象經歷過數次的Minor GC以後仍然存活,將被移入年老代。

年老代:年老代中用來存放從年輕代過來的長時間使用的對象,大部分的JVM內存溢出錯誤均發生在這個區域。當年老代被過分佔用,沒法存放下更多的數據時,jvm會發起一次年老代GC(Major GC\Full GC),該類型GC會釋放年老代中的資源,雖然該GC觸發頻率很低,可是對硬件資源的消耗較高,且Full GC過程當中會暫停該線程的執行。若是系統中存在內存泄露,頻繁的觸發Full GC,將會嚴重的佔用服務器資源,形成應用的假死,這也是我以前猜想b的依據。

 

持久代:持久代中用於存放jvm的反射類等,如class等,此區域對GC的影響不大,也不大會發生內存溢出的狀況。

 

下圖是引用網上的一張圖片,更形象的描述了heap區的構成

<2><2>

 

2.3jstat、jmap實戰

ok,在弄清楚jvm的GC機制以後,就有了努力的方向了,爲了弄清楚GC具體的工做狀況,就要使用到jstat命令了。

jstat(Java Virtual Machine Statistics Monitoring Tool)是jdk自帶的監控工具,位置在%JAVA_HOME%/bin 下,命令使用方法爲

 jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]

下圖是我對系統中tomcat進程的監控狀況

<3><3>

<4><4>

命令中 -gcutil表示統計GC狀況,5125爲tomcat的pid,10000表示沒10s統計一次,5表示一共統計5次

結果中s0爲from區,s1爲to區,E爲Eden區,O爲Old區,P爲Permanent區,YGC爲yong GC次數,YGCT爲yong GC執行的總時間,FGC爲Full GC次數,FGCT爲Full GC總時間,GCT爲GC總時間。

上面圖<3>爲cpu佔用率高時的截圖,圖<4>爲正常狀況下截圖。

很明顯的看到GC次數相差不大的狀況下,GC耗時存在很大的差距,推測此時系統中可能存在內存泄漏的狀況。

 

爲了肯定jvm中具體有哪些生存的對象,就須要用到jdk自帶的另外一個監控工具,jmap了

jmap(Memory Map)用於監控系統內存中存活的對象。

使用命令: jmap -histo:live 5125>> /opt/jmap.txt  

其中5125爲pid ,因爲數據較多,將數據保存在txt文件中進行分析,下圖列出了對內存佔用排名前幾的對象

<5><5>

一眼看去,String對象穩居第一,好吧,項目中對String的處理確實有很多問題,可是,排名第三的這是什麼東西?!

在代碼中一查,這個對象只在一個上傳文件中的Servlet中被用到了一次,很明顯的內存泄漏!

 

3.問題解決

很明顯,jspsmart這個插件正是內存泄漏的元兇,網上查找資料以後肯定,jspsmart因爲自身bug,在長時間運行後會產生兩個嚴重問題:
a. 客戶端在未完成上傳時便主動終止了上傳操做,此時客戶端再也不上傳文件,可是服務端仍然會佔用InputStream,而且不會主動釋放,形成cpu佔用率100%,猜想a證明
b. 客戶上傳的文件損壞,在建立File對象時沒法找到文件終止標識,所以一直在建立新的File對象,形成內存泄漏。
 
由此,服務器內存溢出和cpu佔用率100%兩個問題都找到了關鍵所在,接下來的工做就像對簡單了,使用apache的開源項目commons-upload替換原來的jspsmart來完成文件上傳的工做,替換事後,系統資源佔用正常,附上bug修復後的jmap截圖
<6> <6>
相關文章
相關標籤/搜索