小師妹學JVM之:JIT中的PrintCompilation

簡介

上篇文章咱們講到了JIT中的LogCompilation,將編譯的日誌都收集起來,存到日誌文件裏面,而且詳細的解釋了LogCompilation日誌文件中的內容定義。今天咱們再和小師妹一塊兒學習LogCompilation的姊妹篇PrintCompilation,看看都有什麼妙用吧。java

PrintCompilation

小師妹:F師兄,上次你給講的LogCompilation實在是太複雜了,生成的日誌文件又多,徹底看不了,我其實只是想知道有哪些方法被編譯成了機器碼,有沒有什麼更加簡單的辦法呢?git

真理的大海,讓未發現的一切事物躺臥在個人眼前,任我去探尋- 牛頓(英國)

固然有的,那就給你介紹一下LogCompilation的妹妹PrintCompilation,爲何是妹妹呢?由於PrintCompilation輸出的日誌要比LogCompilation少太多了。github

老規矩,上上咱們的JMH運行代碼,文章中使用的代碼連接都會在文末註明,這裏使用圖片的緣由只是爲了方便讀者閱讀代碼:多線程

這裏和上次的LogCompilation不一樣的是,咱們使用:-XX:+PrintCompilation參數。架構

其實咱們還能夠添加更多的參數,例如:app

-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation

先講一下-Xbatch。 jvm

通常來講JIT編譯器使用的是和主線程徹底不一樣的新的線程。這樣作的好處就是JIT能夠和主線程並行執行,編譯器的運行基本上不會影響到主線程的的運行。學習

可是有陰就有陽,有利就有弊。多線程在提升的處理速度的同時,帶給咱們的就是輸出日誌的混亂。由於是並行執行的,咱們主線程的日誌中,穿插了JIT編譯器的線程日誌。優化

若是使用-Xbatch就能夠強迫JIT編譯器使用主線程。這樣咱們的輸出日誌就是井井有理的。真棒。this

再講一下TieredCompilation。

爲了更好的提高編譯效率,JVM在JDK7中引入了分層編譯Tiered compilation的概念。

大概來講分層編譯能夠分爲三層:

第一層就是禁用C1和C2編譯器,這個時候沒有JIT進行。
第二層就是隻開啓C1編譯器,由於C1編譯器只會進行一些簡單的JIT優化,因此這個能夠應對常規狀況。
第三層就是同時開啓C1和C2編譯器。

在JDK8中,分層編譯是默認開啓的。由於不一樣的編譯級別處理編譯的時間是不同的,後面層級的編譯器啓動的要比前面層級的編譯器要慢,可是優化的程度更高。

這樣咱們其實會產生不少中間的優化代碼,這裏咱們只是想分析最終的優化代碼,因此咱們須要中止分層編譯的功能。

最後是今天的主角:PrintCompilation。

PrintCompilation將會輸出被編譯方法的統計信息,所以使用PrintCompilation能夠很方便的看出哪些是熱點代碼。熱點代碼也就意味着存在着被優化的可能性。

分析PrintCompilation的結果

小師妹:F師兄,我照着你的例子運行了一下,結果果真清爽了不少。但是我仍是看不懂。

沒有一我的能全面把握真理。小師妹,咱們始終在未知的路上前行。不懂就問,不會就學。

咱們再截個圖看一下生成的日誌吧。

由於日誌太長了,爲了節約你們的流量,我只截取了開頭的部分和結尾的部分。

你們能夠看到開頭部分基本上都是java自帶的類的優化。只有最後纔是咱們本身寫的類。

第一列是方法開始編譯的時間。

第二列是簡單的index。

第三列是一系列的flag的組合,有下面幾個flag:

b    Blocking compiler (always set for client)
*    Generating a native wrapper
%    On stack replacement (where the compiled code is running)
!    Method has exception handlers
s    Method declared as synchronized
n    Method declared as native
made non entrant    compilation was wrong/incomplete, no future callers will use this version
made zombie         code is not in use and ready for GC

若是咱們沒有關閉分層編譯的話,在方法名前面還會有數字,表示是使用的那個編譯器。

分層編譯詳細的來講能夠分爲5個級別。

0表示是使用解釋器,不使用JIT編譯。
1,2,3是使用C1編譯器(client)。
4是使用C2編譯器(server)。

如今讓咱們來看一下最後一列。

最後一列包含了方法名和方法的長度。注意這裏的長度指的是字節碼的長度。

若是字節碼被編譯成爲機器碼,長度會增長不少倍。

總結

本文介紹了JIT中PrintCompilation的使用,並再次複習了JIT中的分層編譯架構。但願你們可以喜歡。

本文的例子https://github.com/ddean2009/learn-java-base-9-to-20

本文做者:flydean程序那些事

本文連接:http://www.flydean.com/jvm-jit-printcompilation/

本文來源:flydean的博客

歡迎關注個人公衆號:程序那些事,更多精彩等着您!

相關文章
相關標籤/搜索