java效能優化--jvm中哪些方法被編譯了?

語言: CN / TW / HK

theme: devui-blue highlight: a11y-dark


持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第23天,點選檢視活動詳情

前面一章講解了關於編譯閾值的內容,介紹了其用途和如何修改。同時也介紹了編譯的部分原理,只有達到編譯閾值才會觸發編譯,同時編譯閾值會週期性減少,導致出現永遠無法編譯的溫熱程式碼,可以通過降低閾值的方式去優化。本章我們來學習如何找到這些溫熱程式碼,對其進行優化。

那些方法被編譯了?

PrintCompilation 標誌

首先我們通過jvm提供的標誌,來看看有哪些方法會被編譯,我們需要開啟PrintCompilation標誌,此標誌預設是關閉的: bash [[email protected] ~]# jinfo -flag PrintCompilation 13577 -XX:-PrintCompilation 這個標誌無法通過jinfo進行動態開啟,所以我們需要重新啟動專案指定引數: bash nohup java -XX:+PrintCompilation -jar weather-forecast-0.0.1-SNAPSHOT.jar >/dev/null & 再次檢視: bash [[email protected] opt]# jinfo -flag PrintCompilation 21405 -XX:+PrintCompilation 前面的文章講到過,-減號表示關閉,+加號表示開啟。

開啟此標誌,每次jvm編譯一個方法,就會列印對應的日誌資訊:

image.png

如上所示只是部分編譯內容。

其格式如下:

| timestamp | compilation_id |attributes | tiered_level | method_name |size| deopt | | --- | --- | --- | --- | --- | --- | --- | | 編譯完成時間,從0開始 | 編譯的id,通常自增1,執行緒排程偶爾會亂序 |程式碼編譯的狀態。有五種標誌:
1)%:棧上替換編譯(OSR)
2)s:同步方法
3)!:帶異常處理的方法
4)b:阻塞模式時發生的編譯,不會列印,後面文章會提到
5)n:分裝本地方法的編譯,為了便於呼叫本地方法| 使用分層編譯後才會列印,列印數字,表示分層編譯級別 | 被編譯方法名字,格式:ClassName:methodName|編譯後大小(位元組) | 發生逆優化, made zombie 或 made not entrant |

關於表格的內容,後面會有文章單獨去介紹。

jstat工具

如果你不想通過重啟的方式去開啟編譯方法的檢測,那麼還可以使用jstat工具。

jstat提供兩個引數去檢視編譯資訊:

  • -compiler

    bash [[email protected] opt]# jstat -compiler 11210 Compiled Failed Invalid Time FailedType FailedMethod 2898 1 0 4.73 1 java/net/URLClassLoader$1 run 如上所示,看到引數分別是:編譯完成數,編譯失敗數,錯誤數,編譯型別,失敗方法名。

    如果你發現自己的某個方法執行很慢,可以通過此命令檢視,是否是因為編譯失敗引起的。 * -printconpilation

    bash [[email protected] opt]# jstat -printcompilation 11210 3000 Compiled Size Type Method 2981 63 1 java/util/concurrent/locks/AbstractQueuedSynchronizer shouldParkAfterFailedAcquire 2985 21 1 java/nio/channels/spi/AbstractSelector isOpen 2987 36 1 java/util/concurrent/locks/AbstractQueuedSynchronizer acquireInterruptibly 2991 98 1 java/util/concurrent/ScheduledThreadPoolExecutor$DelayedWorkQueue siftUp 2993 24 1 java/util/concurrent/ThreadPoolExecutor$Worker tryRelease 2997 65 1 java/util/concurrent/ScheduledThreadPoolExecutor$ScheduledFutureTask setNextRunTime 如上所示,檢視最近哪些方法被編譯了。每3000毫秒列印一次。