Jvm 學(xué)習(xí)——異常處理

          異常表

          每一個try語句塊catch的異常都與異常表中的一項(xiàng)相對應(yīng),異常表中的每一項(xiàng)都包括:

          1. 起點(diǎn)
          2. 終點(diǎn),始終把catch異常位置的pc指針偏移量的最大值大1
          3.  處理異常時跳轉(zhuǎn)到的字節(jié)碼序列中的pc指針偏移量
          4.  catch的異常類的常量池索引

           

          例如:

          public class Test {
              
          public static void main(String[] args) {

                  
          try {
                      Class.forName(
          "java.lang.String");
                  }
           catch (ClassNotFoundException e) {
                      e.printStackTrace();
                  }


              }

          }

          javap –c查看字節(jié)碼如下:

           

          Compiled from "Test.java"
          public class Test extends java.lang.Object{
          public Test();
            Code:
             
          0:    aload_0
             
          1:    invokespecial    #1//Method java/lang/Object."<init>":()V
             4:    return

          public static void main(java.lang.String[]);
            Code:
             
          0:    ldc    #2//String java.lang.String
             2:    invokestatic    #3//Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
             5:    pop    
             
          6:    goto    14
             
          9:    astore_1
             
          10:    aload_1
             
          11:    invokevirtual    #5//Method java/lang/ClassNotFoundException.printStackTrace:()V
             14:    return
            Exception table:
             from   to  target type
               
          0     6     9   Class java/lang/ClassNotFoundException
          }

           

          可見ClassNotFoundException異常可能會在0~6之間拋出,9開始處的代碼處理此異常。

           

          當(dāng)產(chǎn)生異常的時候,jvm將會在整個異常表中搜索與之匹配的項(xiàng),如果當(dāng)前pc在異常表入口所指的范圍內(nèi),并且所拋出的異常是此入口所指向的類或者其子類,則跳轉(zhuǎn)到對應(yīng)的處理代碼繼續(xù)執(zhí)行。

           

          方法可能會拋出哪些已檢查異常

          Class文件的attribute_info中保存有Exceptions屬性,記錄著每個方法throws的異常信息。具體的可以查看class類文件格式相關(guān)的文章。

           

          athrow指令從棧頂彈出Throwable對象引用,拋出異常。

           

          finally語句

          jvm規(guī)范中,finally語句是通過jsr/jsr_wret指令實(shí)現(xiàn)的。當(dāng)執(zhí)行jsr/jsr_w的時候?qū)?/span>finally執(zhí)行完成后的返回地址壓入棧中,進(jìn)入finally后會馬上將此地址保存到一個局部變量中,執(zhí)行完成后,ret從此局部變量中取出返回地址。???為什么會先把返回地址保存到局部變量中呢???因?yàn)椋?dāng)從finally語句返回的時候需要將返回地址成棧中彈出,當(dāng)finally語句非正常結(jié)束(break,continue,return, 拋異常)的時候就不用再考慮這個問題。

           

          以下是jvm規(guī)范中Compiling finally的一段:

          void tryFinally() {
              
          try {
                  tryItOut();
              }
           finally {
                  wrapItUp();
              }

          }

          the compiled code is
          Method 
          void tryFinally()
             
          0     aload_0            // Beginning of try block
             1    invokevirtual #6         // Method Example.tryItOut()V
             4     jsr 14            // Call finally block
             7     return            // End of try block
             8     astore_1            // Beginning of handler for any throw
             9     jsr 14            // Call finally block
            12     aload_1            // Push thrown value
            13     athrow            // and rethrow the value to the invoker
            14     astore_2            // Beginning of finally block
            15     aload_0            // Push this
            16     invokevirtual #5         // Method Example.wrapItUp()V
            19     ret 2            // Return from finally block
          Exception table:
                 From     To     Target         Type
              
          0        4        8           any

           

          當(dāng)tryItOut排除任何異常后都將會被異常表中的any項(xiàng)捕獲,執(zhí)行完finally后,會執(zhí)行athrow指令將異常拋出。

           

          jdk的某一個版本開始就不會編譯出編譯出含jsr/jsr_wret的字節(jié)碼了,因?yàn)橛兄噶钌系娜毕荩瑢?dǎo)致jvm的檢驗(yàn)和分析系統(tǒng)出現(xiàn)漏洞。

           

          再說finally的非正常退出

          finally中使用breakcontinuereturn、拋出異常等認(rèn)為是finally的非正常結(jié)束。非正常結(jié)束的時候,ret指令不會被執(zhí)行,很可能會出現(xiàn)意想不到的結(jié)果。如:

           

          public class Test {
              
          public static boolean test(boolean b) {
                  
          while (b) {
                      
          try {
                          
          return true;
                      }
           finally {
                          
          /*
                          break;                          始終返回false
                          continue;                         javac編譯再java執(zhí)行會出現(xiàn)死循環(huán)
                                                          在eclipse中甚至?xí)霈F(xiàn)報(bào)錯:提示找到不main class
                          return false;                     始終返回false
                          throw new RuntimeException("");    拋出異常
                           
          */

                      }

                  }


                  
          return false;
              }


              
          public static void main(String[] args) {
                  System.out.println(test(
          true));
              }

          }


          建議:在寫finally語句的時候,盡量避免非正常結(jié)束!


           

          posted on 2011-05-27 14:39 happyenjoylife 閱讀(2599) 評論(4)  編輯  收藏

          評論

          # re: Jvm 學(xué)習(xí)——異常處理 2011-05-27 16:46 代孕

          來學(xué)習(xí)了,謝謝博主的文章了。  回復(fù)  更多評論   

          # re: Jvm 學(xué)習(xí)——異常處理 2011-05-27 22:02 愛課件

          不錯哦  回復(fù)  更多評論   

          # re: Jvm 學(xué)習(xí)——異常處理 2011-06-03 11:35 程先生

          字節(jié)碼,看不懂啊,去哪里學(xué)習(xí)啊?  回復(fù)  更多評論   

          # re: Jvm 學(xué)習(xí)——異常處理 2011-06-11 18:04 happyenjoylife

          @程先生
          字節(jié)碼可以看jvm規(guī)范,也可以看《深入java虛擬機(jī)》,又可以上網(wǎng)找找
            回復(fù)  更多評論   


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           

          導(dǎo)航

          <2011年6月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          統(tǒng)計(jì)

          常用鏈接

          留言簿

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 青冈县| 吴桥县| 吉林省| 泽州县| 焦作市| 秀山| 铁岭市| 大兴区| 西吉县| 潮州市| 南京市| 宁德市| 保定市| 安西县| 玉山县| 黔东| 莱芜市| 白河县| 长宁区| 弥渡县| 辽中县| 临桂县| 麦盖提县| 江安县| 彭阳县| 新河县| 平山县| 万全县| 澜沧| 定州市| 称多县| 连南| 司法| 车险| 三原县| 廉江市| 涡阳县| 安达市| 万年县| 鄂托克旗| 通州市|