認識Java虛擬機及運行時內存 Java技術體系 Java虛擬機 Java虛擬機內存區域 總結

Java技術體系

按功能劃分

  • Java程序設計語言

  • 各種硬件平臺上的Java虛擬機實現

  • Class文件格式

  • Java類庫API

  • 來自商業機構和開源社區的第三方Java類庫

  • JDK java Development Kit (Java開發最小運行單位Java程序設計語言、Java虛擬機、Java類庫)

  • JRE Java runtime environment (Java運行環境Java類庫API中的Java SE API子集和Java虛擬機)

按服務對象劃分

  • Java Card:支持Java小程序(Applets)運行在小內存設備(如智能卡)上的平臺。

  • Java ME(Micro Edition):支持Java程序運行在移動終端(手機、PDA)上的平臺,對Java API有所精簡,並加入了移動終端的針對性支持。

  • Java SE(Standard Edition):支持面向桌面級應用(如Windows下的應用程序)的Java平臺,提供了完整的Java核心API。

  • Java EE(Enterprise Edition):支持使用多層架構的企業應用(如ERP、MIS、CRM應用)的Java平臺,除了提供Java SE API外,還對其做了大量有針對性的擴充,並提供了相關的部署支持。

Java虛擬機

HotSpot虛擬機(官方JDK均採用HotSpot VM),BEA JRockit(被Oracle 收購後不再開發)和IBM J9虛擬機;

特定設備,Zing虛擬機是一個從HotSpot某舊版代碼分支基礎上獨立出來重新開發的高性能Java虛擬機;

Apache Harmony ,沒有真正地被大規模商業運用過,但是它的許多代碼(主要是Java類庫部分的代碼)被吸納進IBM的JDK 7實現以及Google Android SDK之中,尤其是對Android的發展起了很大推動作用;

Google AndroidDalvik VM,Android 4.4時代,支持提前編譯(Ahead Of Time,AOT)的ART虛擬機迅速崛起,Android 5.0裏ART就全面代替了Dalvik虛擬機;

Graal VM被官方稱爲“Universal VM”和“Polyglot VM”,這是一個在HotSpot虛擬機基礎上增強而成的跨語言全棧虛擬機,可以作爲“任何語言”的運行平臺使用,這裏“任何語言”包括了Java、Scala、Groovy、Kotlin等基於Java虛擬機之上的語言,還包括了C、C++、Rust等基於LLVM的語言,同時支持其他像JavaScript、Ruby、Python和R語言等。Graal VM可以無額外開銷地混合使用這些編程語言,支持不同語言中混用對方的接口和對象,也能夠支持這些語言使用已經編寫好的本地庫文件;

Substrate VM,是一個構建在Graal Compiler上的,支持ahead-of-time (AOT) compilation的編譯及運行框架。

Java虛擬機內存區域

線程私有數據區:虛擬機棧、本地方法棧、程序計數器;

線程共享數據區:方法區,堆。


程序計數器

程序計數器(Program Counter Register)是一塊較小的內存空間,它可以看作是當前線程所執行的字節碼的行號指示器。

由於Java虛擬機的多線程是通過線程輪流切換、分配處理器執行時間的方式來實現的,在任何一個確定的時刻,一個處理器(對於多核處理器來說是一個內核)都只會執行一條線程中的指令。因此,爲了線程切換後能恢復到正確的執行位置,每條線程都需要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲,我們稱這類內存區域爲“線程私有”的內存。

如果線程正在執行的是一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;如果正在執行的是本地(Native)方法,這個計數器值則應爲空(Undefined)。此內存區域是唯一在《Java虛擬機規範》中沒有規定任何OutOfMemoryError情況的區域。

Java虛擬機棧

與程序計數器一樣,Java虛擬機棧(Java Virtual Machine Stack)也是線程私有的,它的生命週期與線程相同。

虛擬機棧描述的是Java方法執行的線程內存模型:每個方法被執行的時候,Java虛擬機都會同步創建一個棧幀(Stack Frame)用於存儲局部變量表、操作數棧、動態連接、方法出口等信息。每一個方法被調用直至執行完畢的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。

如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常;如果Java虛擬機棧容量可以動態擴展,當棧擴展時無法申請到足夠的內存會拋出OutOfMemoryError異常。

本地方法棧

本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別只是虛擬機棧爲虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是爲虛擬機使用到的本地(Native)方法服務。

HotSpot是將虛擬機棧和本地方法棧合併在一起。

Java堆

對於Java應用程序來說,Java堆(Java Heap)是虛擬機所管理的內存中最大的一塊。Java堆是被所有線程共享的一塊內存區域,在虛擬機啓動時創建。此內存區域的唯一目的就是存放對象實例,Java世界裏“幾乎”所有的對象實例都在這裏分配內存。

Java堆是垃圾收集器管理的內存區域,因此一些資料中它也被稱作“GC堆”(Garbage Collected Heap,幸好國內沒翻譯成“垃圾堆”)。

方法區

方法區(Method Area ) 與堆一樣,是各個線程共享的內存區域,它用於存儲已被虛擬機加載的類型信息、常量、靜態變量、即時編譯器編譯後的代碼緩存等數據。

永久代是虛擬機實現方法區內存管理的一種方式,JDK8 放棄了永久代概念,採用JRockit、J9一樣在本地內存中實現的元空間(Meta-space)代替。

運行時常量池

運行時常量池Runtime Constant Pool,方法區中一部分。

Class文件中除了有類的版本、字段、方法、接口等描述信息外,還有一項信息是常量池表(Constant Pool Table),用於存放編譯期生成的各種字面量與符號引用,這部分內容將在類加載後存放到方法區的運行時常量池中。

直接內存

直接內存(Direct Memory)並不是虛擬機運行時數據區的一部分,也不是《Java虛擬機規範》中定義的內存區域。

NIO(New input/output)是JDK1.4中新加入的類,引入了一種基於通道(channel)和緩衝區(buffer)的I/O方式,它可以使用Native函數庫直接分配堆外內存,然後通過堆上的DirectByteBuffer對象對這塊內存進行引用和操作。

直接內存的大小並不受到java堆大小的限制,甚至不受到JVM進程內存大小的限制。它只受限於本機總內存大小以及處理器尋址空間的限制。

總結

本文主要講解了關於JVM虛擬機內存的各個數據區域,如下:

接下來會進一步閱讀《深入理解Java虛擬機》,並進行更多內容的記錄、講解。

歡迎點贊/評論,你們的贊同和鼓勵是我寫作的最大動力!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章