技.藝.道:認識JVM

一、JVM是什麼

JVM全名叫“Java Virtual Machine”,中文名叫“爪哇虛擬機”,是java和java系(如Scala、Kotlin)語言實現平臺無關性的關鍵角色。牛逼但也不玄乎,歸根結底它只是一個軟件而已,也就是運行於操作系統上的一個應用程序,與即時通訊軟件、遊戲這些應用程序沒有本質區別。但還有一點要說,JVM是一個概念,或者說是一類軟件。比如“即時通訊軟件”包括QQ、微信、網易泡泡、飛信等等,“遊戲軟件”包括陰陽師、王者榮耀、和平精英等等。“JVM類軟件”包括Oracle Hotspot(Oracle公司持有的Hotspot虛擬機)、Azul Systems Zing(Azul Systems公司基於Hotspot開發的主打低延遲的虛擬機)、Alibaba AJVM(阿里巴巴公司基於OpenJDK開發了自己的JDK,我們姑且稱其中的JVM爲“Alibaba JVM”,簡稱“AJVM”)等等。即:

即時通訊軟件:

  • QQ、微信、網易泡泡、飛信、......

遊戲軟件:

  • 陰陽師、王者榮耀、和平精英、......

JVM類軟件:

  • Hotspot、Zing、AJVM、......

它們宏觀上所處的位置大概是這樣的,我順便標明瞭Hotspot的作用。

 

二、JVM的結構是什麼樣的?

既然是個應用軟件,那自然應該有很多內部模塊和處理邏輯了,下面我們先看一下它大概長什麼樣?

這是Hotspot 在jdk1.8中結構的示意圖,雖然配色有點野,可是結構該是對的(哪裏不對可以評論教教我)。

我們可以看到,它內部大概分爲了五部分:類裝載器、運行時數據區、本地方法庫、本地方法接口、執行引擎。下面逐一說明他們的作用及結構。

1.類裝載器

功能

類裝載器是用來裝載Class文件的,具體的方式有

  • 從本地系統中直接加載
  • 通過網絡下載.class文件
  • 從zip,jar等歸檔文件中加載.class文件
  • 從專有數據庫中提取.class文件
  • 將Java源文件動態編譯爲.class文件

加載流程

類加載的過程包括了加載、驗證、準備、解析、初始化五個階段。其中的驗證、準備、解析三個階段也被稱爲連接階段。

加載、驗證、準備和初始化這四個階段發生的順序是確定的,而解析階段則不一定,它在某些情況下可以在初始化階段之後開始,這是爲了支持Java語言的運行時綁定(也稱爲動態綁定或晚期綁定)

2.運行時數據區

程序運行需要一定的內存空間用來存儲諸如程序的代碼、類名、方法名、變量名、對象、對象的引用等,這個內存空間就被稱爲運行時方法區。根據存儲的對象的不同,運行時方法區被分爲了五個區域。分別是方法區、Java棧、堆、本地方法棧、程序計數器。

2.1 方法區(元空間):

方法區主要存放已被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據(比如spring 使用IOC或者AOP創建bean時,或者使用cglib,反射的形式動態生成class信息等)。它是線程共享的,需要考慮線程安全問題。

方法區在jdk1.8中的實現,叫做“元空間”。它被設計放在操作系統的內存之中。

ClassLoader

用來存放類加載器信息。

Class

用來存放類信息。

常量池

用來存放程序運行中的常量。

而在jdk1.8之前的jdk,如jdk1.6中,方法區的實現叫做“永久代”。

2.2 堆

英文名叫heap,作用是存儲對象實體,即各種類的實例化對象。它是線程共享的,需要考慮線程安全問題。它是GC的主戰場。

 

新生代

包含伊甸園區,倖存區。倖存區有兩塊,他們交替作爲from區和to區。

老年代

存放從新生代倖存區晉升過來的大齡對象。當新生代連續空間不多的時候,也會有體積很大的對象在此處誕生。

StringTable

串池,當創建一個字符串變量時,會先從串池中搜索是否存在該字符串,若有,則直接引用,若沒有,則創建該字符串並將其添加到串池,並引用。它的本質是一個HashTable,大小是固定的不可擴容。

  • 常量池中的字符串僅是符號,第一次用到時才變爲對象。
  • 利用串池的機制,來避免重複創建字符串對象。
  • 字符串變量的拼接原理是StringBuilder(1.8)。
  • 字符串常量的拼接原理是編譯期優化。
  • 可以使用intern方法,主動將串池中還沒有的字符串對象放入串池
    • 1.8 將這個字符串對象嘗試放入串池,如果有則並不放入,若沒有則放入,會把串池中的對象返回。
    • 1.6 將這個字符串對象嘗試放入串池,如果有則並不放入,若沒有則複製一份放入,會把串池中的對象返回。

動態拼接的字符串,不會放在串池,只會存在於堆中。除非主動調用intern方法。

(StringTable是從jdk1.7開始,從原來的方法區常量池挪到堆中的)

2.3 本地方法庫

本地方法:在java中,存在一些由其他語言實現的方法,比如c++/c,它們通常是用來控制底層資源的方法。它們通常由native修飾。

本地方法庫就是用來存放這些所需的本地方法的地方。

2.4 本地方法接口

程序在調用本地方法時,是通過其接口來調用的。這些端口就存放在這裏。

2.5 執行引擎

即基於代碼邏輯和數據進行運算的地方。是程序的實際執行者。

說明:

jdk1.7的更新:StringTable的移動

jdk1.8的更新:方法區的重新實現

GC:內容過多,需要單獨開一篇來講

 

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