前言
入門JVM垃圾回收機制後,接下來可以學習性能調優了。主要有兩部分內容:
- JDK工具的使用。
- 調優策略。
兵器譜
jps
列出正在運行的虛擬機進程,用法如下:
jps [-option] [hostid]
選項 | 作用 |
---|---|
q | 只輸出LVMID,省略主類的名稱 |
m | 輸出main method的參數 |
l | 輸出完全的包名,應用主類名,jar的完全路徑名 |
v | 輸出jvm參數 |
jstat
監視虛擬機運行狀態信息,使用方式:
選項 | 作用 |
---|---|
gc | 輸出每個堆區域的當前可用空間以及已用空間,GC執行的總次數,GC操作累計所花費的時間。 |
gccapactiy | 輸出每個堆區域的最小空間限制(ms)/最大空間限制(mx),當前大小,每個區域之上執行GC的次數。(不輸出當前已用空間以及GC執行時間)。 |
gccause | 輸出-gcutil提供的信息以及最後一次執行GC的發生原因和當前所執行的GC的發生原因。 |
gcnew | 輸出新生代空間的GC性能數據。 |
gcnewcapacity | 輸出新生代空間的大小的統計數據。 |
gcold | 輸出老年代空間的GC性能數據。 |
gcoldcapacity | 輸出老年代空間的大小的統計數據。 |
gcpermcapacity | 輸出持久帶空間的大小的統計數據。 |
gcutil | 輸出每個堆區域使用佔比,以及GC執行的總次數和GC操作所花費的事件。 |
比如:
jstat -gc 28389 1s
每隔1秒輸出一次JVM運行信息:
jmap
生成堆存儲快照,使用方式:
jstack
生成虛擬機當前時刻的線程快照,幫助定位線程出現長時間停頓的原因,用法:
jstack <pid>
Monitor
Monitor是 Java中用以實現線程之間的互斥與協作的主要手段,它可以看成是對象或者Class的鎖。每一個對象都有,也僅有一個 monitor。下面這個圖,描述了線程和 Monitor之間關係,以及線程的狀態轉換圖:
進入區(Entrt Set):表示線程通過synchronized要求獲取對象的鎖,但並未得到。
擁有者(The Owner):表示線程成功競爭到對象鎖。
等待區(Wait Set):表示線程通過對象的wait方法,釋放對象的鎖,並在等待區等待被喚醒。
線程狀態
- NEW,未啓動的。不會出現在Dump中。
- RUNNABLE,在虛擬機內執行的。
- BLOCKED,等待獲得監視器鎖。
- WATING,無限期等待另一個線程執行特定操作。
- TIMED_WATING,有時限的等待另一個線程的特定操作。
- TERMINATED,已退出的。
舉個例子:
線程狀態:
t1沒有搶到鎖,所以顯示BLOCKED。t2搶到了鎖,但是處於睡眠中,所以顯示TIMED_WAITING,有限等待某個條件來喚醒。 把睡眠的代碼去掉,線程狀態變成了:
t1顯示RUNNABLE,說明正在運行,這裏需要額外說明一下,如果這個線程正在查詢數據庫,但是數據庫發生死鎖,雖然線程顯示在運行,實際上並沒有工作,對於IO型的線程別隻用線程狀態來判斷工作是否正常。 把MyTask的代碼小改一下,線程拿到鎖之後執行wait,釋放鎖,進入等待區。
線程狀態如下:
兩個線程都顯示WAITING,這次是無限期的,需要重新獲得鎖,所以後面跟了on object monitor。
再來個死鎖的例子:
線程狀態:
這個有點像哲學家就餐問題,每個線程都持有對方需要的鎖,那就運行不下去了。
調優策略
兩個基本原則:
- 將轉移到老年代的對象數量降到最少。
- 減少Full GC的執行時間。目標是Minor GC時間在100ms以內,Full GC時間在1s以內。
主要調優參數:
設定堆內存大小,這是最基本的。
- -Xms:啓動JVM時的堆內存空間。
- -Xmx:堆內存最大限制。
設定新生代大小。
新生代不宜太小,否則會有大量對象涌入老年代。
- -XX:NewRatio:新生代和老年代的佔比。
- -XX:NewSize:新生代空間。
- -XX:SurvivorRatio:伊甸園空間和倖存者空間的佔比。
- -XX:MaxTenuringThreshold:對象進入老年代的年齡閾值。
設定垃圾回收器
年輕代:-XX:+UseParNewGC。
老年代:-XX:+UseConcMarkSweepGC。
CMS可以將STW時間降到最低,但是不對內存進行壓縮,有可能出現“並行模式失敗”。比如老年代空間還有300MB空間,但是一些10MB的對象無法被順序的存儲。這時候會觸發壓縮處理,但是CMS GC模式下的壓縮處理時間要比Parallel GC長很多。
G1採用”標記-整理“算法,解決了內存碎片問題,建立了可預測的停頓時間類型,能讓使用者指定在一個長度爲M毫秒的時間段內,消耗在垃圾收集上的時間不得超過N毫秒。