方法內聯
方法內聯能夠觸發更多的優化。通常而言,內聯越多,生成代碼的執行效率越高。然而,對于即時編譯器來說,內聯越多,編譯時間也就越長,而程序達到峰值性能的時刻也將被推遲。
內聯意味著有編譯,編譯后的機器碼要存到 Codecache 中,而 Codecache 內存是有固定大小的由 Java 虛擬機參數 -XX:ReservedCodeCacheSize 控制),如果 Codecache 滿了,則會帶來性能問題
虛方法的內聯
通過判斷虛方法的目標是否唯一
- 唯一, 完全去虛化
直接內聯
- 不唯一, 條件去虛化
向代碼中增添類型比較,內聯不同類型目標的虛方法
將虛方法調用轉換為一個個的類型測試以及對應該類型的直接調用
HotSpot虛擬機的intrinsic
intrinsic 與方法內聯
- 獨立的樁程序
- 解釋執行器(Interpreter):解釋執行器在執行代碼時,如果遇到對原方法的調用,可以直接跳轉到對應的樁程序執行,而不是執行原方法的字節碼。這樣可以減少方法調用的開銷,并可能使用更高效的實現
- 即時編譯器(JIT Compiler):即時編譯器在將字節碼編譯為機器碼時,會將代表對原方法調用的中間表示(IR)節點替換為對樁程序的調用。這種替換發生在編譯過程中,使得生成的機器碼直接調用樁程序,而不是原方法
- 特殊的編譯器 IR 節點
- 即時編譯器(JIT Compiler):即時編譯器會將對原方法的調用的 IR 節點,替換成特殊的 IR 節點,并參與接下來的優化過程。最終,即時編譯器的后端將根據這些特殊的 IR 節點,生成指定的 CPU 指令
逃逸分析
一種確定指針動態范圍的靜態分析,它可以分析在程序的哪些地方可以訪問到指針
- 對象是否被存入堆中(靜態字段或者堆中對象的實例字段)
- 對象是否被傳入未知代碼中。
判斷對象是否會被外部方法引用或線程共享
基于逃逸分析的優化
- 棧上分配:如果對象不會逃逸到方法外部,可以直接在棧上分配內存,而不是在堆上分配,從而減少垃圾回收的壓力。由于JVM大多基于對象分布在堆上而進行的優化, 故引入了標量替換
- 標量替換:將對象拆分為基本類型(標量),直接在棧上分配這些基本類型,避免對象的創建。
class Foo {
int a = 0;
}
static int bar(int x) { static int bar (int x){
Foo foo = new Foo(); int a = x;
foo.a = x; return a;
return foo.a; }
}
-
同步消除:如果對象不被多個線程共享消除不必要的同步操作
synchronized (new Object()) {}以提高性能
部分逃逸分析
Graal中存在此優化(C2中無)
public static void bar(boolean cond) {
Object foo = new Object();
if (cond) {
foo.hashCode();
}
}
// 優化后代碼類似:
public static void bar(boolean cond) {
if (cond) {
Object foo = new Object();
foo.hashCode();
}
}
部分逃逸分析通過考慮程序的控制流,能夠在對象僅在部分路徑中逃逸時進行優化,將對象的創建推遲到必要的分支中執行
XMM寄存器
由于普通寄存器只有32b 8字節,影響對數組向量的優化 故引入了XMM寄存器

c[i:i+3] = b[i:i+3]+c[i:i+3]

注解處理器
package java.lang;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
測試框架JMH(待完善)
generated-sources
具體來說,它們之間的繼承關系是MyBenchmark_jmhType -> B3 -> B2 -> B1 -> MyBenchmark(這里A -> B代表 A 繼承 B)。其中,B2 存放著 JMH 用來控制基準測試的各項字段。
為了避免這些控制字段對MyBenchmark類中的字段造成 false sharing 的影響,JMH 生成了 B1 和 B3,分別存放了 256 個 Boolean 字段,從而避免 B2 中的字段與MyBenchmark類、MyBenchmark_jmhType類中的字段(或內存里下一個對象中的字段)會出現在同一緩存行中。
注解@
@Fork允許開發人員指定所要 Fork 出的 Java 虛擬機的數目。@BenchmarkMode允許指定性能數據的格式。@Warmup和@Measurement允許配置預熱迭代或者測試迭代的數目,每個迭代的時間以及每個操作包含多少次對測試方法的調用。@State允許配置測試程序的狀態。測試前對程序狀態的初始化以及測試后對程序狀態的恢復或者校驗可分別通過@Setup和@TearDown來實現。
JNI的運行機制(非重要)
native 方法的鏈接
- 讓 Java 虛擬機自動查找符合默認命名規范的 C 函數
// foo.c
#include <stdio.h>
#include "org_example_Foo.h"
JNIEXPORT void JNICALL Java_org_example_Foo_bar__Ljava_lang_String_2Ljava_lang_Object_2
(JNIEnv *env, jobject thisObject, jstring str, jobject obj) {
printf("Hello, World\n");
return;
}
- C 代碼中主動鏈接
JNI的 API

浙公網安備 33010602011771號