深入理解Java虛擬機器----(七)位元組碼執行引擎
阿新 • • 發佈:2019-02-06
位元組碼執行引擎是執行引擎是最重要的一部分,概念模型的總體外觀是一致的:輸入位元組碼,過程是位元組碼解析的等效過程,輸出結果。不同的虛擬機器有不同的具體實現,大體有解釋執行和編譯執行兩種選擇。
執行時棧幀結構:
棧楨在虛擬機器棧中,是支援方法呼叫和執行的結構。儲存區域性變量表、運算元棧、動態連結和方法返回地址等。在編譯時,需要多大的區域性表量表,多深的運算元棧都確定了,所以需要多大記憶體也確定了。只有處於棧頂部的“當前棧楨”,才是有效的。
方法呼叫: 方法的呼叫在class檔案裡,只是符號引用的形式。直到類載入階段甚至執行時,才能確定記憶體入口--直接引用。
- 區域性變量表:存放方法引數和區域性變數。以變數槽存放資料,變數槽有索引,從0開始。0是當前物件的引用,用this關鍵字可以獲取。其餘是其他引數和區域性變數,虛擬機器通過索引取值。區域性變數不像類變數,不會賦初始值,沒賦值過就不能使用。
- 運算元棧:方法進入時是空的,許多指令會不停的吧資料出入棧。算數指令會對棧內資料計算,寫回結果;方法呼叫會用運算元棧傳遞引數。
- 動態連結:指向執行時常量池中,該棧楨所屬方法的引用。為了支援方法呼叫過程中的動態連結。
- 方法返回地址:方法退出時,需要回到上層呼叫的位置。棧楨需要儲存這個地址。
方法呼叫: 方法的呼叫在class檔案裡,只是符號引用的形式。直到類載入階段甚至執行時,才能確定記憶體入口--直接引用。
- 解析:在類載入的解析階段,將一部分的符號引用轉換為直接引用,前提是執行前有一個確定版本,而且不可變,這種叫解析。主要包括:靜態方法、私有方法、例項構造器、父類方法。這是一個靜態的過程。
- 分派:分派可能是靜態,也可能是動態。根據宗量數可分為單分派和多分派。於是就有4種可能。
- 靜態分派:靜態分派發生在編譯階段,典型應用是過載
- 靜態分派:靜態分派發生在編譯階段,典型應用是過載
- 動態分派:和重寫有很大關係。invokevirtual的過程大概是,找到找到運算元棧頂第一個元素的實際型別C。在C中查詢與常量中完全相符的方法,如果找不到就層層往上,查詢父類。這個過程第一步就是找實際型別,然後直接找方法執行。這就是重寫的本質。這種執行時動態的確定執行版本的過程,稱為動態分派。
- 單分派、多分派:方法的接受者和引數,總稱為方法的宗量。單分派就是根據一個宗量對方法進行選擇。多分派當然就是根據多個宗量選擇。
- 靜態分派需要根據靜態型別和引數確定,所以是多分派的。而動態分派已經確定了引數資訊,只需確定方法接收者的實際型別。所以動態分派是單分派。由此可見,java是一門靜態多分派、動態單分派的語言。
- 反射是模擬Java程式碼層面的方法呼叫,MehtodHandler是位元組碼層面的。MehtodHandler中的幾個find方法對應著幾個方法呼叫指令。
- 反射中,Method包含了方法各種各樣的複雜資訊,是重量級的。而MehtodHandler只包含執行該方法的相關資訊,是輕量級的。
- MehtodHandler是對位元組碼指令的模擬,虛擬機器的優化可以應用到上面,反射則不行。
- 反射是為了Java服務的,而MehtodHandler是為了虛擬機器服務,可以支援虛擬機器上的多種語言。