JVM調優總結


在這裏,假設你已經讀過《深入理解Java虛擬機》或者類似的書籍或查看過官方文檔。

這個話題從爲什麼開始。

在虛擬機執行時,有時候會遇到各種線上問題。比如CPU使用居高不下,內存消耗過多,IO讀寫頻繁等問題。我們得找到相應的方法來確定問題所在,再想出對策。

CPU佔用問題

1、CPU佔用高原因分析

原因a: 線程上下文切換消耗。

每個cpu或多核cpu中的一核,同一時間只能執行一個線程。在Java應用中,進行文件IO操作、網絡IO操作、鎖等待或者線程Sleep時,當前線程會進入阻塞或休眠狀態,從而觸發線程上下文切換,上下文切換過於頻繁會造成內核佔用過多的cpu資源,導致應用的響應變慢。

原因b:cpu上的運行隊列。

每個核上處理runnable的線程的線程線反應其負載(load),load越大,核用越長的時間來完成。(建議每個核上load爲1-3個)

原因c:cpu的利用率。

cpu利用率:用戶進程、內核、中斷處理、IO等待以及空閒五個部分組成。用戶進程佔用65-70%爲宜,而內核佔用爲30-35%左右。

查看cpu使用情況工具

可用top或pidstat來查看cpu的使用情況。

top

使用top命令後,第三行爲我們比較關注的信息。us(用戶佔用)、sy(系統佔用)、ni(改變優先級佔用)、id(空閒)。

對於多核cpu,可以按1顯示每核的消耗情況。

以上默認爲進程信息,如果要看線程信息,可以按shift+h來顯示。

pidstat

此工具可以查看線程佔用cpu情況,輸入pidstat 1 2,表示在控制檯上一秒輸出一次,一共輸出2次。可以多次查看。

分析cpu佔用高的各種情況

us:用戶佔用高

top之後,發現us的百分比過高,表明應用消耗大部分cpu。我們得找到線程id,轉換成16進制(linux上),再採用kill -3 [javapid]或jstack [javapid]來查看或dump導出查看。

當然,這部分佔用高可能的原因是:線程一直處於runnable狀態,通常是無阻塞、循環、正則或純粹計算動作。

另一個可能是頻繁的GC,最主要是Full GC。要從JVM內存消耗上查找原因。

sy:內核佔用高

top之後,sy佔用高,說明linux花費太多時間用於切換線程,造成這種情況主要原因是java應用啓動的線程過多,且這些應用不斷處於阻塞和執行狀態變化之中,導致了操作系統要不斷的進行線程上下文切換。按照上面的方法導出線程信息,查看線程狀態、鎖信息,找出等待狀態或鎖競爭過多的線程。

文件IO消耗

原因分析

在linux上,物理空閒內存夠用,通常只有寫文件時或者第一次讀取文件時纔會產生真正IO。

文件IO消耗的跟蹤工具

pidstat

輸入 pidstat -d -t - p [pid] 1 100,查看指定進程的io和額外信息。找到其中的io消耗高的線程,之後結合jstack來進一步分析,找到對應的java代碼。

網線IO消耗

暫時略

內存消耗

內存消耗原因分析

多數生產情況下,通常將-Xms和-Xmx設爲相同的值,避免運行期頻繁申請內存。目前只有創建線程和使用Direct ByteBuffer時纔會操作jvm堆外的內存。JVM內存消耗過多會導致GC執行頻繁,CPU消耗增加。應用執行速度嚴重下降,嚴重會造成OutOfMemeryError,導致java進程退出。所以出現內存消耗過大問題時,根據以下詳細分析,找出是jvm外的物理內存佔用還是JVM Heap區。

如果os物理內存消耗過大,可能是JVM內存設置過大、創建的線程過多或Direct ByteBuffer往物理內存裏放置過多的對象造成。

堆內存設置比物理內存大更容易出現問題。

Direct ByteBuffer是直接使用物理內存的,但是GC負責回收釋放。

創建的線程數也會影響物理內存,這取決於-Xss值的大小,也取決於棧的深度。

內存查看工具

top

此工具查看的進行佔用情況不太準,查看的爲進程的佔用全部內存。因爲jvm啓用時,會按照堆內存設置提前佔據內存空間,但不表明在jvm裏此內存已經被使用。

pidstat

pidstat -r -p [pid] [interval] [times],可查看指定進程的內存佔用信息(包括物理內存和虛擬內存)。

程序執行慢的原因

鎖競爭激烈

硬件資源未充分

工具的常用命令:

jstack:

jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP

1)、options:

executable Java executable from which the core dump was produced.

(可能是產生core dump的java可執行程序)

core 將被打印信息的core dump文件

remote-hostname-or-IP 遠程debug服務的主機名或ip

server-id 唯一id,假如一臺主機上多個遠程debug服務

2)、基本參數:

-F當’jstack [-l] pid’沒有相應的時候強制打印棧信息

-l長列表. 打印關於鎖的附加信息,例如屬於java.util.concurrent的ownable synchronizers列表.

-m打印java和native c/c++框架的所有棧信息.

-h | -help打印幫助信息

pid 需要被打印配置信息的java進程id,可以用jps查詢.

pidstat

pidstat [ 選項 ] [ <時間間隔> ] [ <次數> ]

常用的參數:

-u:默認的參數,顯示各個進程的cpu使用統計
-r:顯示各個進程的內存使用統計
-d:顯示各個進程的IO使用情況
-p:指定進程號
-w:顯示每個進程的上下文切換情況
-t:顯示選擇任務的線程的統計信息外的額外信息
-T { TASK | CHILD | ALL }
這個選項指定了pidstat監控的。TASK表示報告獨立的task,CHILD關鍵字表示報告進程下所有線程統計信息。ALL表示報告獨立的task和task下面的所有線程。
注意:task和子線程的全局的統計信息和pidstat選項無關。這些統計信息不會對應到當前的統計間隔,這些統計信息只有在子線程kill或者完成的時候纔會被收集。
-V:版本號
-h:在一行上顯示了所有活動,這樣其他程序可以容易解析。
-I:在SMP環境,表示任務的CPU使用率/內核數量
-l:顯示命令名和所有參數

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章