棧幀與操做數棧剖析及符號引用與直接引用的轉換

 咱們知道在Java中異常處理有兩種方式,一種是try...catch...一下,這個在上一次【http://www.javashuo.com/article/p-vnazcvwt-gt.html】中已經進行了詳細且完整的分析,可是還缺乏往方法上throws的狀況,因此這裏對其進行補充一下,先修改源代碼:html

固然啦這個throws沒啥意義,由於咱們在代碼塊中捕獲了,但這裏只是爲了說明問題,而後編譯再用jclasslib查看一下:java

其中也能理解Code指的是方法體中的相關的字節信息,以下:c++

那點開「Exceptions」查看一下內容:web

那若是咱們拋出一個運行期的異常,好比NullPointException ,那還會在這個「Exceptions」中呈現麼,試試:數據結構

再次編譯查看字節:學習

也是會反饋的,因此須要明確的是:在方法全中try...catch..和throws異常在字節碼中是不同的。關於異常這塊的東東就學到這了,接下來則會進入另外一個新的東東。spa

棧幀與操做數棧剖析:htm

先來輸出一下理論:對象

棧幀【stack frame】:是用於幫助虛擬機執行方法調用與方法執行的數據結構。自己是一種數據結構,封裝了方法的局部變量表【以前已經學習過了】、動態連接信息【像c++在編譯期就肯定了類與類之間的關係,而java則不同,在編譯期間是不知道類之間的關係的,只有在類加載或真正調用時才能知道類之間的關第,基於此就出現了符號引用與直接引用,也就是下面會學到的】、方法的返回地址【當一個方法調用目標方法時,最終目標方法會返回方法調用方的位置處,因此須要記錄下來方法返回的地址信息】以及操做數棧【以前已經學習過了】等信息。blog

下面用一個形象的圖來描述一下,其實對於方法調用都是以棧幀的形式存在於棧中:

而對於方法代碼的執行就存在出棧與入棧兩個操做,JVM對於操做都是基於棧的,好比說兩個數的減法:3-2 = 1,對於這個操做JVM是如何完成的呢,下面來畫一下:
先把3壓入到棧中:

而後再把2也壓入棧:

 而後須要對這兩個數進行減法操做,因此會有相關的減法指令,當看到該減法指令以後,由於會涉及到兩個操做數,因此會從棧中彈出兩個數,首先將2彈出:

此時棧中就只有3了:

而後再把3彈出棧:

此時棧爲空棧了:

最後將計算的結果1壓入到棧中:

另外再來講一下局部變量,存儲局部變量的最小單位稱爲slot,好比說有10個局部變量則會有10個slot來進行存儲,可是這也不是絕對的,由於數據類型的長度是不同的,像比較短的short、int等類型的長度較短,一個slot就能夠存儲下,那對於long、double佔據長度比較多的類型就會用兩個連續的slot來表示,固然啦對於要多個slot來表示的一個局部變量要讀的話也是讀連續的幾個slot,否則就數據不對了;另外對於10個局部變量不是必定得要10個slot來存儲的,由於slot是能夠複用的,咱們知道方法體中的局部變量出了方法做用域就會回收,可是方法體裏面又是能夠N多個更小的做用域的,怎麼理解,寫一個僞代碼:

而對於方法局部變量表中是不會區分是不是更小的做用域的,都當一個局部變量對待,而若是像上面b和c出了做用域生命週期結束以後,那麼這兩個局部變量的slot有可能會給下面的d和e重複使用,固然啦也有可能不復用,具體得看JVM的具體實現,總之須要明確的是:對於10個局部變量,有可能須要10個slot,也有可能不須要這麼多。

符號引用與直接引用的轉換:

關於符號引用和直接引用在學JVM開篇就提出過,我們再來回憶一下:

有些符號引用是在類加載階段或是第一次使用時就會轉換成直接引用,這種轉換叫作靜態解析;另一些符號引用則是在每次運行期轉換爲直接引用,這種轉換叫作動態連接,這體現爲Java的多態性。好比說下面的多態代碼:

很是要注意的是:在編譯期間字節碼看到的a.sleep()全是Animal的,涉及到invokevirsual指令,而該指令主要是動態派發的指令,它會檢查a真正指向那個對象在運行期間會動態的轉換成真正指向那個對象的sleep()了,因此對於這段代碼有3個a.sleep(),則會進行三次的轉換,關於invokevirsual指令在以後會詳細進行說明,目前先有個理論概念在於腦海既可。

相關文章
相關標籤/搜索