標籤:spec store 解釋 基礎 rgs 操作 ini type bsp
原文地址:
https://my.oschina.net/bieber/blog/703251
一、單層的try/catch
public int test(int a,int b){ try{ return a+b; }catch (Exception e){ throw new CustomException(); }}
通過javap -v查看JVM編譯成class位元組碼之後是如何處理這個try/catch的
public int test(int, int); flags: ACC_PUBLIC Code: stack=2, locals=4, args_size=3 0: iload_1 // 將第一個int參數壓入隊列(第一個入參) 1: iload_2 // 將第二個int參數壓入隊列(第二個入參) 2: iadd //彈出隊列中第一個和第二個參數執行相加,並把相加結果壓入隊列 3: ireturn //彈出隊列第一個元素,並return。 4: astore_3 //此處是try開始的邏輯 5: new #3 // class com/bieber/demo/CustomException 8: dup 9: invokespecial #4 // Method com/bieber/demo/CustomException."<init>":()V 12: athrow //將隊列中的第一個元素彈出,併當做異常拋出,到此整個方法體完畢 Exception table: from to target type 0 3 4 Class java/lang/Exception LineNumberTable: line 13: 0 line 14: 4 line 15: 5 LocalVariableTable: Start Length Slot Name Signature 5 8 3 e Ljava/lang/Exception; 0 13 0 this Lcom/cainiao/cilogisticservice/ExceptionClass; 0 13 1 a I 0 13 2 b I StackMapTable: number_of_entries = 1 frame_type = 68 /* same_locals_1_stack_item */ stack = [ class java/lang/Exception ]
View Code
上面是test方法JVM編譯之後的結果,上面的Code塊是整個方法體的內容,而從0-3可以視為是方法體的正常邏輯,4-12可以視為try/catch塊,從方法體的指令看,正常情況下執行到3的地方就完畢了,而不會去執行4-12的指令。
那就得出結論,try/catch代碼塊在正常邏輯的時候是不會被執行的,於是對於對代碼加上try/catch塊,並不會影響代碼的執行效率,因為根本不會有多餘的指令被執行,只有出現異常的時候才會多出執行異常的指令。
上面的JVM編譯的位元組碼的時候除了Code代碼塊,還有Exception table代碼塊,從這個代碼塊的內容可以看到,包含四列(from,to,target,type),其中from和to表示這個try/catch代碼塊是從哪開始到哪結束,可以看到上面的try/catch代碼塊是從Code代碼塊的0-3,也就是從載入第一個int值到返回結果的代碼塊,target表示這個try/catch代碼塊執行邏輯在哪裡開始,比如上面的表示從Code中的4開始,也就是astore_3指令開始,直到athrow指令被執行的地方,在Exception table中的一行還有type列,表示是這個異常類型,用於在一個try/catch代碼塊出現多個catch內容,用於匹配正確的異常類型。
二、一個try對應多個catch
public int test(int a,int b){ try{ return a+b; }catch (Exception e){ a++; throw new CustomException(); }catch (Throwable t){ b++; throw new CustomException(); } }
JVM對上面代碼編譯後的結果:
public int test(int, int); flags: ACC_PUBLIC Code: stack=2, locals=4, args_size=3 0: iload_1 1: iload_2 2: iadd 3: ireturn 4: astore_3 5: iinc 1, 1 8: new #3 // class com/bieber/demo/CustomException 11: dup 12: invokespecial #4 // Method com/bieber/demo/CustomException."<init>":()V 15: athrow 16: astore_3 17: iinc 2, 1 20: new #3 // class com/cainiao/cilogisticservice/CustomException 23: dup 24: invokespecial #4 // Method com/cainiao/cilogisticservice/CustomException."<init>":()V 27: athrow Exception table: from to target type 0 3 4 Class java/lang/Exception 0 3 16 Class java/lang/Throwable LineNumberTable: line 13: 0 line 14: 4 line 15: 5 line 16: 8 line 17: 16 line 18: 17 line 19: 20 LocalVariableTable: Start Length Slot Name Signature 5 11 3 e Ljava/lang/Exception; 17 11 3 t Ljava/lang/Throwable; 0 28 0 this Lcom/cainiao/cilogisticservice/ExceptionClass; 0 28 1 a I 0 28 2 b I StackMapTable: number_of_entries = 2 frame_type = 68 /* same_locals_1_stack_item */ stack = [ class java/lang/Exception ] frame_type = 75 /* same_locals_1_stack_item */ stack = [ class java/lang/Throwable ]
View Code
和上面的內容對比一下會發現,在Code中多出了一段astore_3/athrow塊,並且在Exception table中多了一行,想想通過上面的解釋,對這個多出的一行的目的應該都知道是用來什麼的,由於我在catch中成了throw之外,還多了一個++的操作,可以看到在astore_3/athrow塊中多出了iinc指令,所以可以理解,try/catch在JVM中對應的是一個子代碼塊,在條件滿足(出現匹配的catch異常)的時候會被執行。
下面我整理一下當出現異常的(這裡說的是有try/catch的異常)JVM處理流程:
1、在try/catch出現異常2、JVM會去`Exception table`尋找匹配的異常類型3、假設匹配上了,那麼讀取from,to,target,擷取待執行的`try/catch`塊的指令(具體是否拋出,看是否有athrow指令)。
三、try/finally塊的執行處理
public int test(int a,int b){ try{ return a+b; }catch (Exception e){ a++; throw new CustomException(); }finally { b++; } }
JVM編譯後的指令:
public int test(int, int); flags: ACC_PUBLIC Code: stack=2, locals=5, args_size=3 0: iload_1 1: iload_2 2: iadd 3: istore_3 //將棧頂的元素儲存局部變數數組的第三個位置 4: iinc 2, 1 //執行b++ 7: iload_3 //把局部變數第三個位置的數值壓入棧頂 8: ireturn //彈出棧頂,並且返回 9: astore_3 10: iinc 1, 1 //a++ 13: new #3 // class com/bieber/demo/CustomException 16: dup 17: invokespecial #4 // Method com/bieber/demo/CustomException."<init>":()V 20: athrow 21: astore 4 23: iinc 2, 1 //b++ 26: aload 4 28: athrow Exception table: from to target type 0 4 9 Class java/lang/Exception 0 4 21 any 9 23 21 any LineNumberTable: line 13: 0 line 18: 4 line 14: 9 line 15: 10 line 16: 13 line 18: 21 LocalVariableTable: Start Length Slot Name Signature 10 11 3 e Ljava/lang/Exception; 0 29 0 this Lcom/cainiao/cilogisticservice/ExceptionClass; 0 29 1 a I 0 29 2 b I StackMapTable: number_of_entries = 2 frame_type = 73 /* same_locals_1_stack_item */ stack = [ class java/lang/Exception ] frame_type = 75 /* same_locals_1_stack_item */ stack = [ class java/lang/Throwable ]
View Code
通過上面的代碼,你會發現在Exception table都出了兩行,其實我們只是在代碼中只有一個try/catch塊,而這裡出現了三個,那麼另外兩個是做什麼的呢?可以看到多出的兩行的type都是any,這裡的any表示的是任何異常類型,多出的第一行,是從0-4,表示0-4之間的指令出現異常,會從21的指令開始執行,發現執行的是b++(finally)的內容,多出的第二行是9-23,表示9-23之間的指令被執行的過程中出現異常也會從21行開始執行(也是執行finally的內容),而9-23其實是catch的代碼邏輯。上面均是出現了異常會觸發finally的代碼執行,正常情況下會發現4的位置執行了finally的內容,然後再執行ireturn指令,這裡可以得出,JVM處理finally其實是對於正常的指令隊列增加了finally代碼塊的指令,以及對異常中添加了finally代碼塊的指令,這也就導致了fianlly在任何地方都可以被執行,其實就是冗餘了指令隊列(其實思想比較簡單)。
java-基礎-【三】try/catch/finally