1. 程式人生 > >小師妹學JVM之:JDK14中JVM的效能優化

小師妹學JVM之:JDK14中JVM的效能優化

[toc] # 簡介 上一篇文章我們講到了JVM為了提升解釋的效能,引入了JIT編譯器,今天我們再來從整體的角度,帶小師妹看看JDK14中的JVM有哪些優化的方面,並且能夠從中間得到那些啟發。 更多精彩內容且看: * [區塊鏈從入門到放棄系列教程-涵蓋密碼學,超級賬本,以太坊,Libra,比特幣等持續更新](http://www.flydean.com/blockchain/) * [Spring Boot 2.X系列教程:七天從無到有掌握Spring Boot-持續更新](http://www.flydean.com/learn-spring-boot/) * [Spring 5.X系列教程:滿足你對Spring5的一切想象-持續更新](http://www.flydean.com/spring5/) * [java程式設計師從小工到專家成神之路(2020版)-持續更新中,附詳細文章教程](http://www.flydean.com/java-roadmap-2020/) # String壓縮 小師妹:F師兄,上次你給我講的JIT真的是受益匪淺,原來JVM中還有這麼多不為人知的小故事。不知道除了JIT之外,JVM還有沒有其他的效能提升的姿勢呢? 姿勢當然有很多種,先講一下之前提到過的,在JDK9中引入的字串壓縮。 在JDK9之前,String的底層儲存結構是char[],一個char需要佔用兩個位元組的儲存單位。 因為大部分的String都是以Latin-1字元編碼來表示的,只需要一個位元組儲存就夠了,兩個位元組完全是浪費。 於是在JDK9之後,字串的底層儲存變成了byte[]。 目前String支援兩種編碼格式LATIN1和UTF16。 LATIN1需要用一個位元組來儲存。而UTF16需要使用2個位元組或者4個位元組來儲存。 在JDK9中,字串壓縮是預設開啟的。你可以使用 ~~~java -XX:-CompactStrings ~~~ 來控制它。 # 分層編譯(Tiered Compilation) 為了提升JIT的編譯效率,並且滿足不同層次的編譯需求,引入了分層編譯的概念。 大概來說分層編譯可以分為三層: 1. 第一層就是禁用C1和C2編譯器,這個時候沒有JIT進行。 2. 第二層就是隻開啟C1編譯器,因為C1編譯器只會進行一些簡單的JIT優化,所以這個可以應對常規情況。 3. 第三層就是同時開啟C1和C2編譯器。 在JDK7中,你可以使用下面的命令來開啟分層編譯: ~~~java -XX:+TieredCompilation ~~~ 而在JDK8之後,恭喜你,分層編譯已經是預設的選項了,不用再手動開啟。 # Code Cache分層 Code Cache就是用來儲存編譯過的機器碼的記憶體空間。也就說JIT編譯產生的機器碼,都是存放在Code Cache中的。 Code Cache是以單個heap形式組織起來的連續的記憶體空間。 如果只是用一個code heap,或多或少的就會引起效能問題。為了提升code cache的利用效率,JVM引入了Code Cache分層技術。 分層技術是什麼意思呢? 就是把不同型別的機器碼分門別類的放好,優點嘛就是方便JVM掃描查詢,減少了快取的碎片,從而提升了效率。 下面是Code Cache的三種分層: ![](https://img-blog.csdnimg.cn/20200528225431671.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_0,text_aHR0cDovL3d3dy5mbHlkZWFuLmNvbQ==,size_35,color_8F8F8F,t_70) # 新的JIT編譯器Graal 之前的文章我們介紹JIT編譯器,講的是JIT編譯器是用C/C++來編寫的。 而新版的Graal JIT編譯器則是用java來編寫的。對的,你沒看錯,使用java編寫的JIT編譯器。 有沒有一種雞生蛋,蛋生雞的感覺?不過,這都不重要,重要的是Graal真的可以提升JIT的編譯效能。 Graal是和JDK一起發行的,作為一個內部的模組:jdk.internal.vm.compiler。 Graal和JVM是通過JVMCI(JVM Compiler Interface)來進行通訊的。其中JVMCI也是一個內部的模組:jdk.internal.vm.ci。 > 注意,Graal只在Linux-64版的JVM中支援,你需要使用 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler 來開啟Graal特性。 # 前置編譯 我們知道在JIT中,通常為了找到熱點程式碼,JVM是需要等待程式碼執行一定的時間之後,才開始進行原生代碼的編譯。這樣做的缺點就是需要比較長的時間。 同樣的,如果是重複的程式碼,沒有被編譯成為機器碼,那麼對效能就會有影響。 而AOT(Ahead-of-time)就厲害了,看名字就知道是提前編譯的意思,根本就不需要等待,而是在JVM啟動之前就開始編譯了。 AOT提供了一個java tool,名字叫做jaotc。顯示jaotc的命令格式: ~~~java jaotc