當前位置:
首頁 > 知識 > Try-catch-finally在JVM底層都幹了些啥?

Try-catch-finally在JVM底層都幹了些啥?

讓我們準備一個函數:

然後,反編譯他的位元組碼:

首先我們介紹異常表:在編譯生成的位元組碼中,每個方法都附帶一個異常表。

異常表中的每一個條目代表一個異常處理器,並且由 from 指針、to 指針、target 指針以及所捕獲的異常類型構成。這些指針的值是位元組碼索引用以定位位元組碼。

下圖就是我特別指出的JVM位元組碼中的異常表部分。

我們來分析一下這幾個語句的執行流程,首先執行:

這相當於執行:

再來:

上圖相當於執行

有人問:try去哪了?

我馬上就要介紹。此時idiv執行完就有異常了,有異常了先找異常表。

我再貼一下異常表,他是怎麼搜索的呢?

當程序觸發異常時,Java 虛擬機會從上至下遍歷異常表中的所有條目。

當觸發異常的位元組碼的索引值在某個異常表條目的監控範圍內,Java 虛擬機會判斷所拋出的異常和該條目想要捕獲的異常是否匹配。

如果匹配,Java 虛擬機會將控制流轉移至該條目 target 指針指向的位元組碼。

我們看 ,是第四個索引指向的位元組碼出了問題,顯然,此時應該匹配紅線這一條記錄,從而跳轉到第14個索引的位元組碼。

我們看他怎麼做的?

new出一個RuntimeException並拋出,它就是

這一句,按照我們剛才的流程,此時依然需要找到這個RuntimeException在哪個異常表的條目中

此時匹配到異常表的條目,跳轉到位元組碼索引23

繼續拋出RuntimeExcpetion,可以注意到 這實際上對應了

這個語句,於是我們可以知道,在三個都出現異常的情況下,實際上最終向外拋出的異常是finally裡面的異常。

可以看到當31索引處調用athrow語句拋出異常時,此時異常表沒有任何一個條目能夠匹配該異常,此時怎麼辦呢?

如果遍歷完所有異常表條目,Java 虛擬機仍未匹配到異常處理器,那麼它會彈出當前方法對應的 Java 棧幀,並且在調用者中重複上述操作。

在最壞情況下,Java 虛擬機需要遍歷當前線程 Java 棧上所有方法的異常表

事實上分析以上的整體的全部語句你可以發現,jvm層面有真正的finally嗎?

沒有

現在的做法是,複製 finally 代碼塊的內容,分別放在 try-catch 代碼塊所有正常執行路徑以及異常執行路徑的出口中。無論是否出現異常,確保一定會執行finally語句。

剛才catch出了異常,依然執行finally語句就可以發現這一點。至於其他路徑,大家可以自行驗證。我就在這裡拋磚引玉了。

至於為什麼2-6發生任何異常都跳轉到23?大家可以自己想一下這個問題。

我就提示一點 2-6 target為14的條目代表的catch是不能捕獲所有異常的,但是你要確保finally的語句能夠執行。而2-6恰巧是try語句塊的內容。23這個索引恰巧是finally語句的一份複製。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 千鋒JAVA開發學院 的精彩文章:

TAG:千鋒JAVA開發學院 |