熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

詳細介紹JVM結構基礎

2013-11-23 18:51:55  來源: Java核心技術 

  JVM執行的對象就是大家非常熟悉的class文件我們也稱為類文件JVM規范定義的這個編譯完成的代碼文件(雖然並非強制要求是實際的文件)的格式非常的詳實但是我們這裡只說一些宏觀的內容以後有機會再研究細節的內容吧JVM要求的類文件的格式是和硬件和操作系統無關的一種二進制格式它精確定義了類或者接口的表示它甚至包含了字節順序這樣的細節而字節順序在特定平台的目標文件格式中一般都是固定的不會進行說明

  JVM所支持的數據類型和Java語言規范中定義的幾乎一樣請注意是幾乎一樣!也就是原始類型和引用類型他們可以被存儲在變量表中也可以作為參數傳遞被方法返回更通常的就是成為操作的對象為什麼和Java語言規范中定義的不完全一樣呢?因為JVM中有一種Java語言所沒有的原始類型返回地址類型(returnAddress type)該類型是jsr ret以及jsr_w指令需要使用到的它的值是JVM指令的操作碼的指針並且它的值是不能被運行中的程序所修改的

  另外需要提到的就是布爾類型的值雖然在Java語言中它是完全獨立的值但是在JVM中只提供了對它的有限支持表現在

  沒有單獨的操作布爾類型的指令源代碼中的布爾類型的操作在編譯以後是作為int類型的值進行操作的

  JVM直接支持布爾數組newarray指令可以創建布爾數組而它的訪問和修改操作卻是使用byte類型的數組的操作指令進行的baloadbastore(在JDK以及布爾數組被編碼為byte數組每個元素是位)

  JVM用代表true代表false編譯器將源代碼中的布爾類型映射為JVM中的int類型而且必須和JVM的要求一致

  另外JVM規范中對於浮點類型的數據有大段的說明我沒有怎麼看主要是討論JVM的浮點型和IEEE 的關系的

  關於類型的另外一個需要提一下的是類型檢查JVM期望幾乎所有的類型檢查已經在運行之前完成了(通常是由編譯器進行檢查的)而不用JVM自己來檢查原始類型的值不需要被標記或者在運行時被檢查以確定他們的類型同樣他們也不用和引用類型的值進行區分區分工作是由JVM的指令集來完成的JVM的指令集使用不同指令來區分它要操作的值的類型例如iadd ladd fadd以及dadd是用於將兩個數字相加並產生數字類型結果的所有JVM指令但是每個指令都是針對特定類型的分別對應int long float以及double

  JVM包含對對象的顯式支持類是動態分配的類實例或者是一個數組JVM中的引用類型就是對一個對象的引用引用類型的值可以想象為對象的指針一個對象同時可能存在多個對它的引用對象總是通過引用被操作傳遞或者測試的

  對於引用類型需要提及的一點就是關於null它最初是沒有運行時類型的但是它可以被轉換為任何類型而且對於nullJVM並沒有要求任何具體的值與之對應

  說完上面這些我們就開始進入我學習JVM時最想了解的部分了大家可要打起精神哦

  JVM為運行一個程序定義了幾種數據區(Data Area)包括pc寄存器JVM堆棧方法區(Method Area)運行時常量池(Runtime Constant Pool)以及本機方法堆棧(Native Method Stacks)這些數據區根據其生存期可以分為兩種一種就是和JVM的生存期相同(包括堆和方法區)一種和線程的生存期相同(其它的)和JVM生存期相同的數據區在JVM啟動的時候被創建並在JVM退出的時候被銷毀而和線程生存期相同的數據區是每個線程一個的他們在線程創建的時候被創建在線程被銷毀的時候被銷毀

  

  由於JVM可以同時支持運行多個線程因此每個線程必然需要各自的PC(program counter)寄存器無論從什麼角度講每個JVM線程只能在一個時間只能執行一個方法該方法也就是線程的當前方法如果該方法不是本機方法那麼PC寄存器保存的就是當前指令(JVM的指令)的地址如果是當前方法是本機方法PC寄存器的值就沒有被定義JVM的PC寄存器的大小足夠大可以容納一個returnAddress類型或者特定平台的本機指針

  每個JVM線程還擁有一個私有的JVM堆棧它存儲幀(下一篇文章會講到)JVM堆棧和像C這樣的傳統編程語言中的堆棧是類似的它保存局部變量和部分結果並且在方法調用和返回中也擔任一些職責因為除了對幀的壓入和彈出操作外對JVM堆棧不能直接進行操作因此幀可能是在堆上分配的如果一個線程中計算所需的JVM堆棧大於允許的大小JVM會拋出StackOverflowError錯誤如果JVM堆棧是可以動態伸縮的如果需要擴展但是又沒有足夠的內存可用或者沒有足夠的內存為一個新線程創建JVM堆棧JVM會拋出OutOfMemoryError錯誤

  JVM只有一個為所有線程所共享的堆所有的類實例和數組都是在堆中創建的堆所存儲的對象被一個自動存儲管理系統回收(也就是我們所熟知的垃圾收集器(gc))對象不能被顯式的釋放JVM假設沒有特定類型的自動存儲管理系統存儲管理技術可以根據實現者的系統需求進行選擇如果計算所需的內存堆大於自動存儲管理系統可以使用的大小JVM會拋出OutOfMemoryError錯誤

  JVM只有一個為所有的線程所共享的方法區方法區類似傳統語言的已編譯代碼的存儲區或者UNIX進程的文本它存儲類結構例如運行時常量池成員和方法數據以及方法構造方法的代碼(包括用於類和實例的初始化以及接口類型初始化的特定方法(這些特定方法以後會講到))雖然從邏輯上講方法區是堆的一部分但是JVM的簡單實現可以選擇不對方法區進行垃圾收集或者壓縮(以筆者的理解就是類不能進行卸載)最新版本(第二版)的JVM規范沒有要求方法區的位置或者管理已編譯代碼的策略如果方法區的內存不能滿足一個分配請求JVM會拋出OutOfMemoryError

  運行時常量池是類文件中的常量池表的運行時表示它包含幾種常量范圍從編譯時就已知的數字常量到運行時必須進行解析的方法和成員引用運行時常量池扮演的功能類似於傳統編程語言中的符號表(symbol table)但是它所包含的數據比典型的符號表更多

  每個運行時常量池時從JVM的方法區中分配的對於特定方法或者接口的運行時常量池是JVM在創建類或者接口的時候創建的

  當創建一個類或者接口時如果創建運行時常量池需要的內存比方法區中的可用內容更多的內存JVM會拋出OutOfMemoryError

  關於常量池創建的更多內容以後可能會更詳細的講解

  JVM的實現可能使用傳統的堆棧(更通常的講就是C棧)以支持本機方法(不是使用JAVA語言編寫的方法)本機方法堆棧也可以用於在像C語言這樣的語言中為JVM指令集實現解析器對於不能加載本機方法以及自身不依賴傳統堆棧的JVM實現而言它可以不提供本機方法堆棧如果提供本機方法堆棧通常在線程創建的時候為每個線程分配(以筆者的理解應該是需要使用本機方法的線程)如果線程計算所需的內存比本機方法堆棧所允許的大JVM會拋出StackOverflowError錯誤如果本機方法堆棧可以動態伸縮而當需要擴展的時候又沒有足夠的內存時或者沒有足夠的內容用於創建一個本機方法堆棧JVM會拋出OutOfMemoryError

  對於上面的這些數據區JVM規范允許它們的大小是固定尺寸的也可以是根據計算的需要動態伸縮的如果是固定尺寸的其尺寸可以在創建時自主選擇JVM的實現可以給程序員或者用戶提供控制JVM堆棧的初始大小的方法同樣在動態伸縮的情況下可以控制最大大小和最小大小並且它們所使用的內存空間可以不是連續的


From:http://tw.wingwit.com/Article/program/Java/hx/201311/25878.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.