2015年9月27日 星期日

JVM 實作初步心得

前陣子的GBA模擬器實作戰實又中離了,跳回了今年二月有小摸的JVM實作嘗試,當時的進度大概到剖析class檔,了解一下class大概結構,parse出一些初步的東西後就沒繼續下去了,到最近又重回jvm研究.

JVM這一東西,其實可以分成好幾個層面和區塊來看待,如果要寫出最基本的JVM概念雛形,而且能跑些東西的,我現在是做到了,真的說起來並沒有多難,不過如果要完整實作JVM所有的功能部分,以我來說來得下一些功夫,至於寫好後如果要再討論到校能改善議題.記憶體使用效率等等,那就可以說真的昰一門專的研究了,光是初步實作jvm到能跑些簡單demo的階段,應該只能算是學習JVM的運作機制原理.

目前跑起來有些感想,有人說JVM像是一個硬體的模擬器或是虛擬機器,像是一個軟體製作的CPU一樣,我得說我有點持反對的看法,與其說它像是一個軟體的處理器,我倒覺得它比較像是處理程序罷了,真的把它視為硬體來看待分類的話,它歸納於stack machine,跟多數一般我們所認知的處理器register machine差異很大(我想你能說得出來,列舉出來所聽聞的cpu都是register machine).....

stack machine真正硬體上的實作,以聞名的來說很少,運作效率來說肯定不可能比register machine好,為何?  撇開軟體虛擬的不談,即使是真正硬體上的實機也是一樣,原因是stack machine在進行一些資料處理或是運算實,免不了得把資料一下子放到stack,一下子從stack內取出,這一來一往,縱然是最簡單的加減乘除,實際運作步驟就是多register machine的處理方式相當多倍.

回到軟體實作的jvm虛擬機,我真的很懷疑這東西如果真的硬體具現化的話能不能達成或是好不好達成,估計很多部分的功能得刪減,但因為我非硬體專業,這邊就不多評論.

整個JVM的運作分成很多環節,最起步驟,你得把class file的內部結構給k完,並且設計出一套資料結構來放置parse出來的class內容,classfile的內容簡單來說就是一大堆的資料結構,一層包著一層,parse的撰寫方法如果剛開始沒規劃好,對全盤沒了解清楚的話,很容易在parse階段就失敗,但有耐性的話,其實parse並不會太複雜,最主要是說class的資料結構是一層包著一層的,有些資料結構裡面有塞著相同的資料結構,所以在parse的時候某些部分一定要用遞迴的方式比較好處理.

大概就是一堆定義拉...描述拉....分成好幾個節區,還有很多屬性的描述項目,說真的如果只是寫短一點的程式,像是hello world或是迴圈教學的demo,那些定義.描述等等等程式碼bytecode以外的東西可能還比bytecode份量還多, bytecode碼本身並不是唯一的主角,而bytecode碼很多部分的運作也需要搭配那些定義.描述的資料.

如果你能把class檔完整parse完畢,載入到你建立的資料結構內,那開頭最重要的第一步就完成了,再接下去是了解jvm在運作的記憶體模型和stack為主的處理方式,我得說以我實作到現在,我直接感受到的昰JVM的記憶體模型和管理其實才是真正的重頭大戲,bytecode本身反來沒那麼複雜,bytecode所用的opcode為固定一個byte,最多256個指令,但實際上目前還沒那麼多,不到210個,這210個opcode基本上就spec怎麼描述,你了解後照作而已,而且很多的動作都很相似,只是處理的資料類型不同而已,因此真正實作比較需要花功夫的還是JVM記憶體模型的了解.

這邊就只講最基本的部分,jvm因為是stack base,因此所有操作幾乎都離不開跟stack的關係,運作一個method有幾個最重要的主角, 1.PC(program counter) 2.操作 stack 3.local varible array , pc不用談就是指執行bytecode實後處理到位置哪裡的記錄 , 而local varible array 的角色有點像是register mchine的registers,舉個例子來說

public void test(int a, int b , int c)
{
    int d = 23;
   .............................
}

其中船地參數 a b c 和method裡面配置的 d , 這四個數會依序被放入到 local varible array 內,然後接下來的操作過程,就是一步一步把 local varible array 內的 item 塞入到 操作stack中,一下子push . 一下子又pop 來回好幾次 ,最後算出結果.........就是這樣.

跟一般硬體的pc不同,每進入到一個method內,它都有自己獨立的pc,當然也有自己獨立的資料區域,所以如果在method中又進入method,就又會有另一份 pc . stack . local varible array ,我們可以把這獨立的記憶體資料結構視為是一個frame stack,因為可能method裡面會呼叫method,然後重複進入,形成遞迴的行為,所以stack frame也是會動態增加的,每進入method,stack frame就隨之新增,到離開後stack frame就被pop移出.

(其實也沒特別需要去實作frame stack...一般程式語言遞迴處裡下去就好,效果一樣的)

上面說的只是jvm的一個運作部分,還有共享資料區域等等不少沒談到,因為也還沒實作到,而建立物件.繼承.多thread那幾塊也還沒去摸到.....看來看去都是記憶體管理的學問比較重.

跟我當初所想像的不同,撰寫JVM比較不那麼像真正在寫硬體或是遊戲主機的模擬器,反來比較像是了解一門學問或是軟體處裡的方法,class檔的運作也不同於遊戲 rom , 與其實說class像是機械碼這種東西,還不如說它比較像是描述或是定義,連CODE的部分在JVM內也被這樣看待成是屬性描述的一部分罷了....

如果真的有硬體實作版的JVM,我比較好奇能夠實做到哪種程度,畢竟有些比較適合用軟體去呈現.

說真的了解內容後,對JVM的興趣反來降低一些,也許會到某種程度後到一段落.

跟jvm相比LLVM更接近於真正硬體上的概念,以後有空再來看看.


沒有留言:

張貼留言