逃逸分析:分析變量是否逃出它的作用域
- 全局變量賦值逃逸
- 方法返回值逃逸
- 實例引用逃逸
- 線程逃逸:賦值給類變量或者可以在其他線程中訪問的實例變量
public class EscapeTest {
public static SomeClass someClass;
// 1
public void globalVariablePointerEscape(){
someClass = new SomeClass();
}
// 2
public SomeClass methodPointerEscape(){
return new SomeClass();
}
// 3 this原本作用於當前對象,通過參數逃逸到SomeClass對象中
public void instancePassPointerEscape(){
this.methodPointerEscape().printClassTime(this);
}
}
class SomeClass {
public void printClassTime(EscapeTest escapeTest) {
System.out.println(escapeTest.getClass().getName());
}
}
逃逸狀態標記
- 全局級別逃逸:一個對象可能從方法或者當前線程中逃逸
- 對象被作爲方法的返回值
- 對象作爲靜態字段( static field)或者成員變量(field)
- 如果重寫了某個類的 finalize()方法,那麼這個類的對象都會被標記爲全局逃逸狀態並且一定會放在堆內存中。
- 參數級別逃逸
- 對象被作爲參數傳遞給一個方法,但是在這個方法之外無法訪問/對其他線程不可見。
- 無逃逸:一個對象不會逃逸。
標量替換
標量是指不能進一步分解的變量,包括基礎數據類型、對象引用。聚合量是指可以進一步分解的量。
通過逃逸分析確定該對象不會被外部訪問,並且對象可以被進一步分解時,JVM不會創建該對象,而是創建它的成員變量來代替。-XX:+EliminateAllocations
開啓標量替換(JDK8默認開啓)
public void someTest(){
SomeTest someTest = new SomeTest();
someTest.id = 1;
someTest.age = 2;
// 開啓標量替換後,不會再創建對象,而是轉換爲變量
int id = 1;
int age = 2;
}
棧上分配
通過逃逸分析,能夠確認對象不會被外部訪問,就會在棧上分配對象。對象佔用的空間在方法結束棧幀出棧時銷燬,減輕GC壓力。