当前位置:网站首页>JVM(4) 字節碼技術+運行期優化

JVM(4) 字節碼技術+運行期優化

2022-06-29 19:20:00 Demon_bh

字節碼技術

1、類文件結構

   ca fe ba be 00 00 00 34 00 23 0a 00 06 00 15 09
  • 前4個字節為魔數:cafababe
  • 下來2個字節為小版本號:00 00
  • 下來2個字節為大版本號:00 34 —> 52 (對應jdk1.8, 45為jdk1.1)

2、字節碼指令

使用 javap 工具反編譯 class 文件:

   javap -v D:Demo.class

3、方法執行流程

在這裏插入圖片描述

  • 虛擬機棧:方法局部變量錶+操作數棧+動態連接+返回地址
  • 局部變量錶以slot為最小單比特,存放方法參數和局部變量

4、异常處理

finally 中的字節碼被複制了 3 份,分別放入 try 流程,catch 流程以及 catch 剩餘的异常類型流程。
注意:雖然從字節碼指令看來,每個塊中都有 finally 塊,但是 finally 塊中的代碼只會被執行一次

    public class Code_18_FinallyReturnTest {
    

        public static void main(String[] args) {
    
            int i = Code_18_FinallyReturnTest.test();
            // 結果為 20
            System.out.println(i);
        }

        public static int test() {
    
            int i;
            try {
    
                i = 10;
                return i;
            } finally {
    
                i = 20;
                return i;
            }
        }
    }
  • 如果在 finally 中出現了 return,會吞掉异常
  • finally 中有return,會覆蓋try中的return
  • 字節碼將异常信息顯示在异常錶

5、語法糖

  • 默認構造器

  • 自動拆裝箱(jdk1.5之前不能自動)

  • 泛型擦除

  • 可變參數(public static void foo(String… args){})

  • foreach()自動轉換為for(i=0; i<n;i++)或集合的迭代器Iterator遍曆

  • switch

  • try-with-resources(省去在finally中關閉資源,且能保留關閉資源時的异常)

  • 方法重寫時的橋接方法(子類返回值可以是父類返回值的子類–>jvm自動轉換)

  • 匿名內部類(自動生成一個類)

運行期優化

1)即時編譯

HotSpot是解釋器與編譯器並存的

  • 對於大部分的代碼采取解釋執行的方式運行;

  • 對於小部分運行頻繁的熱點代碼,將其編譯成機器碼提高執行效率,以達到理想的運行速度。

分層編譯
JVM 將執行狀態分成了 5 個層次:

0層:解釋執行,用解釋器將字節碼翻譯為機器碼
1層:使用 C1 即時編譯器編譯執行(不帶 profiling)
2層:使用 C1 即時編譯器編譯執行(帶基本的profiling)
3層:使用 C1 即時編譯器編譯執行(帶完全的profiling)
4層:使用 C2 即時編譯器編譯執行

  • 解釋器:
    • 將字節碼解釋為機器碼,下次即使遇到相同的字節碼,仍會執行重複的解釋
    • 將字節碼解釋為針對所有平臺都通用的機器碼
  • 即時編譯器
    • 將一些字節碼編譯為機器碼,並存入 Code Cache,下次遇到相同的代碼,直接執行,無需再編譯
    • 根據平臺類型,生成平臺特定的機器碼

執行效率上簡單比較一下 Interpreter < C1(Client) < C2(Server)。

2)逃逸分析(Escape Analysis)

Java Hotspot 虛擬機分析新創建對象的動態作用域,並决定是否在 Java 堆上分配內存的一項技術。

當分析該對象不能逃逸到方法或線程外,進行以下優化:

  • 棧上分配(內存直接分配在棧上,對象隨棧幀出棧銷毀)
  • 同步消除
  • 標量替換(不創建對象,只創建用到的成員變量)

3)方法內聯

如果JVM監測到一些小方法被頻繁的執行,它會把方法的調用替換成方法體本身,如:

private int add4(int x1, int x2, int x3, int x4) {
     
	//這裏調用了add2方法
    return add2(x1, x2) + add2(x3, x4);  
}  
private int add2(int x1, int x2) {
      
    return x1 + x2;  
}

方法調用被替換後

private int add4(int x1, int x2, int x3, int x4) {
      
    //被替換為了方法本身
    return x1 + x2 + x3 + x4;  
}
原网站

版权声明
本文为[Demon_bh]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/180/202206291915440430.html