激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - JVM如何處理異常深入詳解

JVM如何處理異常深入詳解

2021-06-28 10:17技術小黑屋 Java教程

異常處理的兩大元素:拋出異常、捕獲異常,非正常處理的兩個方法。下面這篇文章主要給大家介紹了關于JVM如何處理異常的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下

前言

無論你是使用何種編程語言,在日常的開發過程中,都會不可避免的要處理異常。今天本文將嘗試講解一些jvm如何處理異常問題,希望能夠講清楚這個內部的機制,如果對大家有所啟發和幫助,則甚好。

當異常不僅僅是異常

我們在標題中提到了異常,然而這里指的異常并不是單純的exception,而是更為寬泛的throwable。只是我們工作中習以為常的將它們(錯誤地)這樣稱謂。

關于exception和throwable的關系簡單描述一下

  • exception屬于throwable的子類,throwable的另一個重要的子類是error
  • throw可以拋出的都是throwable和其子類,catch可捕獲的也是throwable和其子類。

除此之外,但是exception也有一些需要我們再次強調的

  • exception分為兩種類型,一種為checked exception,另一種為unchecked exception
  • checked exception,比如最常見的ioexception,這種異常需要調用處顯式處理,要么使用try catch捕獲,要么再次拋出去。
  • unchecked exception指的是所有繼承自error(包含自身)或者是runtimeexception(包含自身)的類。這些異常不強制在調用處進行處理。但是也可以try catch處理。

注:本文暫不做checked exception設計的好壞的分析。

exception table 異常表

提到jvm處理異常的機制,就需要提及exception table,以下稱為異常表。我們暫且不急于介紹異常表,先看一個簡單的java處理異常的小例子。

?
1
2
3
4
5
6
7
public static void simpletrycatch() {
 try {
 testnpe();
 } catch (exception e) {
 e.printstacktrace();
 }
}

上面的代碼是一個很簡單的例子,用來捕獲處理一個潛在的空指針異常。

當然如果只是看簡簡單單的代碼,我們很難看出什么高深之處,更沒有了今天文章要談論的內容。

所以這里我們需要借助一把神兵利器,它就是javap,一個用來拆解class文件的工具,和javac一樣由jdk提供。

然后我們使用javap來分析這段代碼(需要先使用javac編譯)

?
1
2
3
4
5
6
7
8
9
10
11
12
//javap -c main
 public static void simpletrycatch();
 code:
 0: invokestatic #3   // method testnpe:()v
 3: goto  11
 6: astore_0
 7: aload_0
 8: invokevirtual #5   // method java/lang/exception.printstacktrace:()v
 11: return
 exception table:
 from to target type
  0 3 6 class java/lang/exception

看到上面的代碼,應該會有會心一笑,因為終于看到了exception table,也就是我們要研究的異常表。

異常表中包含了一個或多個異常處理者(exception handler)的信息,這些信息包含如下

  • from 可能發生異常的起始點
  • to 可能發生異常的結束點
  • target 上述from和to之前發生異常后的異常處理者的位置
  • type 異常處理者處理的異常的類信息

那么異常表用在什么時候呢

答案是異常發生的時候,當一個異常發生時

1.jvm會在當前出現異常的方法中,查找異常表,是否有合適的處理者來處理

2.如果當前方法異常表不為空,并且異常符合處理者的from和to節點,并且type也匹配,則jvm調用位于target的調用者來處理。

3.如果上一條未找到合理的處理者,則繼續查找異常表中的剩余條目

4.如果當前方法的異常表無法處理,則向上查找(彈棧處理)剛剛調用該方法的調用處,并重復上面的操作。

5.如果所有的棧幀被彈出,仍然沒有處理,則拋給當前的thread,thread則會終止。

6.如果當前thread為最后一個非守護線程,且未處理異常,則會導致jvm終止運行。

以上就是jvm處理異常的一些機制。

try catch -finally

除了簡單的try-catch外,我們還常常和finally做結合使用。比如這樣的代碼

?
1
2
3
4
5
6
7
8
9
public static void simpletrycatchfinally() {
 try {
 testnpe();
 } catch (exception e) {
 e.printstacktrace();
 } finally {
 system.out.println("finally");
 }
}

同樣我們使用javap分析一下代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void simpletrycatchfinally();
 code:
 0: invokestatic #3   // method testnpe:()v
 3: getstatic #6   // field java/lang/system.out:ljava/io/printstream;
 6: ldc  #7   // string finally
 8: invokevirtual #8   // method java/io/printstream.println:(ljava/lang/string;)v
 11: goto  41
 14: astore_0
 15: aload_0
 16: invokevirtual #5   // method java/lang/exception.printstacktrace:()v
 19: getstatic #6   // field java/lang/system.out:ljava/io/printstream;
 22: ldc  #7   // string finally
 24: invokevirtual #8   // method java/io/printstream.println:(ljava/lang/string;)v
 27: goto  41
 30: astore_1
 31: getstatic #6   // field java/lang/system.out:ljava/io/printstream;
 34: ldc  #7   // string finally
 36: invokevirtual #8   // method java/io/printstream.println:(ljava/lang/string;)v
 39: aload_1
 40: athrow
 41: return
 exception table:
 from to target type
  0 3 14 class java/lang/exception
  0 3 30 any
  14 19 30 any

和之前有所不同,這次

  • 異常表中,有三條數據,而我們僅僅捕獲了一個exception
  • 異常表的后兩個item的type為any

上面的三條異常表item的意思為

  • 如果0到3之間,發生了exception類型的異常,調用14位置的異常處理者。
  • 如果0到3之間,無論發生什么異常,都調用30位置的處理者
  • 如果14到19之間(即catch部分),不論發生什么異常,都調用30位置的處理者。

再次分析上面的java代碼,finally里面的部分已經被提取到了try部分和catch部分。我們再次調一下代碼來看一下

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void simpletrycatchfinally();
 code:
 //try 部分提取finally代碼,如果沒有異常發生,則執行輸出finally操作,直至goto到41位置,執行返回操作。
 
 0: invokestatic #3   // method testnpe:()v
 3: getstatic #6   // field java/lang/system.out:ljava/io/printstream;
 6: ldc  #7   // string finally
 8: invokevirtual #8   // method java/io/printstream.println:(ljava/lang/string;)v
 11: goto  41
 
 //catch部分提取finally代碼,如果沒有異常發生,則執行輸出finally操作,直至執行got到41位置,執行返回操作。
 14: astore_0
 15: aload_0
 16: invokevirtual #5   // method java/lang/exception.printstacktrace:()v
 19: getstatic #6   // field java/lang/system.out:ljava/io/printstream;
 22: ldc  #7   // string finally
 24: invokevirtual #8   // method java/io/printstream.println:(ljava/lang/string;)v
 27: goto  41
 //finally部分的代碼如果被調用,有可能是try部分,也有可能是catch部分發生異常。
 30: astore_1
 31: getstatic #6   // field java/lang/system.out:ljava/io/printstream;
 34: ldc  #7   // string finally
 36: invokevirtual #8   // method java/io/printstream.println:(ljava/lang/string;)v
 39: aload_1
 40: athrow //如果異常沒有被catch捕獲,而是到了這里,執行完finally的語句后,仍然要把這個異常拋出去,傳遞給調用處。
 41: return

catch先后順序的問題

我們在代碼中的catch的順序決定了異常處理者在異常表的位置,所以,越是具體的異常要先處理,否則就會出現下面的問題

?
1
2
3
4
5
6
7
8
9
private static void misusecatchexception() {
 try {
 testnpe();
 } catch (throwable t) {
 t.printstacktrace();
 } catch (exception e) { //error occurs during compilings with tips exception java.lang.exception has already benn caught.
 e.printstacktrace();
 }
}

這段代碼會導致編譯失敗,因為先捕獲throwable后捕獲exception,會導致后面的catch永遠無法被執行。

return 和finally的問題

這算是我們擴展的一個相對比較極端的問題,就是類似這樣的代碼,既有return,又有finally,那么finally導致會不會執行

?
1
2
3
4
5
6
7
8
9
10
public static string trycatchreturn() {
 try {
 testnpe();
 return "ok";
 } catch (exception e) {
 return "error";
 } finally {
 system.out.println("trycatchreturn");
 }
}

答案是finally會執行,那么還是使用上面的方法,我們來看一下為什么finally會執行。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static java.lang.string trycatchreturn();
 code:
 0: invokestatic #3   // method testnpe:()v
 3: ldc  #6   // string ok
 5: astore_0
 6: getstatic #7   // field java/lang/system.out:ljava/io/printstream;
 9: ldc  #8   // string trycatchreturn
 11: invokevirtual #9   // method java/io/printstream.println:(ljava/lang/string;)v
 14: aload_0
 15: areturn 返回ok字符串,areturn意思為return a reference from a method
 16: astore_0
 17: ldc  #10   // string error
 19: astore_1
 20: getstatic #7   // field java/lang/system.out:ljava/io/printstream;
 23: ldc  #8   // string trycatchreturn
 25: invokevirtual #9   // method java/io/printstream.println:(ljava/lang/string;)v
 28: aload_1
 29: areturn //返回error字符串
 30: astore_2
 31: getstatic #7   // field java/lang/system.out:ljava/io/printstream;
 34: ldc  #8   // string trycatchreturn
 36: invokevirtual #9   // method java/io/printstream.println:(ljava/lang/string;)v
 39: aload_2
 40: athrow 如果catch有未處理的異常,拋出去。

行文倉促,加之本人水平有限,有錯誤的地方,請指出。

參考文章:

  • http://blog.jamesdbloom.com/jvminternals.html#exception_table
  • https://blog.takipi.com/the-surprising-truth-of-java-exceptions-what-is-really-going-on-under-the-hood/
  • https://en.wikipedia.org/wiki/java_bytecode_instruction_listings
  • https://dzone.com/articles/the-truth-of-java-exceptions-whats-really-going-on

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。

原文鏈接:https://droidyue.com/blog/2018/10/21/how-jvm-handle-exceptions/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产亚洲欧美一区久久久在 | 激情大乳女做爰办公室韩国 | 日本黄色一级毛片 | 欧美 日韩 亚洲 中文 | 成年免费在线视频 | 色99久久 | 一级毛片一区 | 亚洲精品自在在线观看 | 毛片网站视频 | 国产免费观看电影网站 | 欧美成人精品一区 | 日韩黄a | 大胆在线日本aⅴ免费视频 永久免费毛片 | 欧美视频黄色 | 视频一区二区不卡 | 国产免费观看电影网站 | www.99久久久 | 国产精品高潮视频 | 久久精品艹 | 奇米影视亚洲春色 | 青青草成人免费视频在线 | 日本免费a∨ | 在线免费观看麻豆 | 综合网天天射 | av在线浏览| 久久艹艹艹 | 久久蜜桃精品一区二区三区综合网 | 国产一级毛片网站 | 91短视频在线视频 | 国产亚洲精品综合一区91555 | 视频国产一区二区 | 国产无遮挡一级毛片 | 久久久精品视频免费看 | 国产精品午夜未成人免费观看 | 亚洲最黄视频 | 奶子吧naiziba.cc免费午夜片在线观看 | 国产第一页精品 | 欧美一级精品 | 亚洲第一色婷婷 | 一级黄色在线观看 | 亚洲精品有限 |