從我的理解中,throw
是一個基本的jvm命令。當這個被調用時,JVM「檢查當前調用棧是否可以捕獲它」。如果它不能,那麼java就會像調用返回一樣簡單地彈出調用堆棧。那麼jvm「檢查當前的調用棧是否可以捕獲它」等遞歸。JVM如何知道在運行時何處捕獲異常?
我的問題:JVM如何在算法上知道調用堆棧中的哪個位置可以捕獲給定異常?每個調用堆棧條目中是否存儲了元數據將代碼塊的異常映射到代碼塊?有沒有在堆中的靜態數據結構,以某種方式跟蹤這個?因爲某處必須有數據記錄這一點。
從我的理解中,throw
是一個基本的jvm命令。當這個被調用時,JVM「檢查當前調用棧是否可以捕獲它」。如果它不能,那麼java就會像調用返回一樣簡單地彈出調用堆棧。那麼jvm「檢查當前的調用棧是否可以捕獲它」等遞歸。JVM如何知道在運行時何處捕獲異常?
我的問題:JVM如何在算法上知道調用堆棧中的哪個位置可以捕獲給定異常?每個調用堆棧條目中是否存儲了元數據將代碼塊的異常映射到代碼塊?有沒有在堆中的靜態數據結構,以某種方式跟蹤這個?因爲某處必須有數據記錄這一點。
該JVM specification有關於此的詳細信息。
特別是,section 4.7.3給出了有關異常表的詳細信息,這是一系列條目說明在哪些指令之間捕獲哪些異常。 Section 3.12給出了一個具體的例子。
如何元數據映射到了JIT本機代碼,當然另當別論, - 和具體實現的。例如,可能會有一些映射從本地實時編譯代碼回到原來的位置,字節碼指令的每個位置,此時的異常表可以協商,以找到合適的處理程序回來。
很有意思:) – Mik378
一般而言:當引發異常時,JVM會提取「調用堆棧」。這標識了調用堆棧中每個級別正在執行哪個字節碼或機器指令,以及與該位置關聯的類和方法。然後,對於棧中的每個方法(從異常發生和向後工作的方法開始),JVM在方法的表映射try/catch範圍(在內部類對象中)看字節碼/機器指令範圍。
如果「匹配」在表中找到一種方法,和被拋出異常的類型是一類被用於在找到的範圍監視,則控制被轉移到catch
入口點,之後設置異常成爲一種參數位置,因此catch
子句可以引用它。
如果在表中沒有找到「匹配」,那麼調用堆棧會被有效地「彈出」,將先前的下一個方法放在堆棧頂部,以及上述搜索前一個方法表中的「匹配」的嘗試/捕獲範圍重複。
當然這是一種過度簡化。有很多參與處理finally
範圍,例如額外的邏輯,和幾個「邊緣」的案件。
相關:http://stackoverflow.com/questions/10301244/how-is-multi-catch-implemented-in-java-7 – assylias