[轉帖]相同版本JVM和Java應用,在X86和AArch64平臺效能相差30%,何故?原創

济南小老虎發表於2024-05-23
https://heapdump.cn/article/2661262

編者按:目前許多公司同時使用X86和Aarch642種主流的伺服器。但是相同版本的JVM和Java應用,相同的引數JVM引數,但是應用效能在不同的平臺中表現相差30%,X86遠好於Aarch64平臺。本文分析了一個應用在Aarch64效能下降的例子,發現JVM的CodeCache大小是引起這個效能問題的根源,進而研究什麼導致了不同平臺上Codecache大小的不同。最後筆者給出了不同平臺中該如何設定引數規避該問題。希望本文能給讀者一些啟示:當使用不同的硬體平臺時需要關注底層硬體對於上層應用的影響。

業務在x86和arrach64上同時部署時(相同的JDK和Java應用版本),發現aarch64平臺效能下降嚴重問題。進一步檢視日誌,發現在aarch64平臺中偶有如下情況:
image.png
這代表JVM中的CodeCache滿了,導致編譯停止,未編譯的方法只能解釋執行,進而嚴重影響應用效能。什麼是CodeCache?

CodeCache是什麼

簡單來說,CodeCache用於存放編譯後的方法,主要分為三部分:
1.Non-nmethods:包括執行時Stub,Adapter等。
2.Profiled nmethod:包括會採集資訊的方法,即分層編譯中第2、3層的方法
3.Non-Profiled nmethods:包括不採集資訊的方法,即分層編譯中第1、4層的方法,也包括JNI的方法
注:分層編譯指的是JVM同時存在C1和C2兩種編譯器,C1做一些簡單的編譯最佳化,耗時較短,C2做更多複雜的編譯最佳化,效能較好,編譯耗時較多。分層編譯的觸發在JVM記憶體會根據相應的條件進行觸發,關於更多分層編譯相關知識可以參考官網。
在JDK9之後[1],這些會分配到不同的區域(使用不同區域的優點:查詢、回收等),JDK8中會分配到同一塊區域。
JVM平時會清理一些不可達的方法,例如由於退最佳化等產生的死方法,另外UseCodeCacheFlushing選項(預設開啟),還會清理較老以及執行較少的方法。一旦CodeCache滿了之後,會停止編譯,直到CodeCache有空間,若關閉了UseCodeCacheFlushing選項,則會直接永久停止編譯。
不同的JVM版本以及不同的引數,預設的CodeCache大小不同。JDK11中預設引數下大小為240M,若想獲取(確認)預設情況下的CodeCache大小,建議使用-XX:+PrintFlagsFinal選項獲取ReservedCodeCache的大小。
CodeCache大小主要透過以下選項調節:

OptionDescription
InitialCodeCacheSize 初始的CodeCache大小(單位位元組)
ReservedCodeCacheSize 預留的CodeCache大小,即最大CodeCache大小(單位位元組)
CodeCacheExpansionSize CodeCache每次擴充套件大小(單位位元組)

使用–XX:+PrintCodeCache選項可以列印應用使用的CodeCache情況,如下:
image.png
其中max_used表示應用中使用到的CodeCache大小,據此可以設定合適的ReservedCodeCacheSize值。

AArch64 vs x86_64

我們都知道aarch64和x86分別為RISC和CISC架構,因此程式碼密度方面存在一定差異,在這篇文章[2]中比較了不同指令集下手寫彙編的大小,可以看到aarch64的程式碼密度是RISC架構中較優的,但相比x86_64仍稍差些(其中RISC最差,m68k最好)。

image.png
另外筆者選用業界通用的java測試套dacapo[3]比較aarch64和x86_64下codecache佔用的大小。
image.png
可以看到,在aarch64架構下,CodeCache均比x86_64要大,但根據不同場景,大小差距不同,在5%-20%之間。因此在我們發現相同應用在x86和aarch64上時,CodeCache大小需要進行相應的調節。
除此之外,還需要注意InlineSmallCode選項,JVM只會inline程式碼體積比該值小的方法。JVM透過inline可以觸發更多的最佳化,因此inline對於效能提升也很重要。在JDK11中,InlineSmallCode在x86下的預設值為2000位元組,在aarch64下的預設值為2500位元組。而JDK8中,InlineSmallCode在x86和aarch64下預設值均為2000位元組。因此建議遷移時也相應修改InlineSmallCode的值。

[1] https://bugs.openjdk.java.net/browse/JDK-8015774
[2] http://web.eece.maine.edu/~vweaver/papers/iccd09/ll_document.pdf
[3] http://dacapobench.org/

後記

如果遇到相關技術問題(包括不限於畢昇JDK),可以進入畢昇JDK社群查詢相關資源(點選原文進入官網),包括二進位制下載、程式碼倉庫、使用教學、安裝、學習資料等。畢昇JDK社群每雙週週二舉行技術例會,同時有一個技術交流群討論GCC、LLVM、JDK和V8等相關編譯技術,感興趣的同學可以新增如下微信小助手,回覆Compiler入群。

相關文章