JVM 綜述

概覽

從 JVM 的總體上看,它解決了3個問題:

  1. Java 程序的內(nèi)存管理(GC & 運(yùn)行時數(shù)據(jù)區(qū))。
  2. Java Class 二進(jìn)制字節(jié)流的加載(ClassLoader)。
  3. Java 程序的執(zhí)行(執(zhí)行引擎)。

如下圖所示:

虛擬機(jī)基本架構(gòu)

在我們的日常開發(fā)中,最和我們息息相關(guān)的就是1和2了,比如 GC 調(diào)優(yōu),內(nèi)存故障排查,再比如使用自定義的類加載器去實現(xiàn)一些特定的邏輯,就如我們之前分析的 tomcat 源碼中的類加載器用于隔離不同版本的相同類庫,必須要使用自定義的類加載器。

1. Java 程序的內(nèi)存管理(GC & 運(yùn)行時數(shù)據(jù)區(qū))

1.1. 運(yùn)行時數(shù)據(jù)區(qū)

從上圖中可以看出,虛擬機(jī)內(nèi)存管理主要由幾個部分組成:

  1. Java 堆(存放對象的地方)
  2. Java 棧(在 HotSpot 實現(xiàn)中,本地方法棧和虛擬機(jī)棧合二為一)
  3. PC 寄存器(也稱為程序計數(shù)器)
  4. 方法區(qū)(JDK8 中已經(jīng)將方法區(qū)去除,改為元數(shù)據(jù)區(qū),解決了方法區(qū)----也稱為永久代的內(nèi)存溢出)。
  5. 直接內(nèi)存(大小不限制于 Java 堆,直接向操作系統(tǒng)申請,使用場景于讀寫頻繁的場合,例如 NIO)

1.2. 垃圾回收系統(tǒng)

Java 程序員之所以不需要顯式的釋放內(nèi)存,一切都?xì)w功于 GC,GC 解放了 Java 程序員的雙手。GC 系統(tǒng)會在后臺清除無用的實例對象,釋放內(nèi)存空間。

而 JVM 中的 GC 可謂是一個龐大的系統(tǒng),其中分為幾個部分:

  1. 判斷什么是垃圾對象
  2. 垃圾回收算法
  3. 各種各樣的垃圾收集器

我們將會在后面慢慢講解。

2. Java Class 二進(jìn)制字節(jié)流的加載(ClassLoader)

2.1 類加載器

對于 Java 虛擬機(jī)來說,Class 文件是一個重要的接口,無論使用何種語言進(jìn)行軟件開發(fā),只要能將源文件編譯為正確的 Class 文件,那么這種語言就可以在 Java 虛擬機(jī)上運(yùn)行??梢哉f,Class 文件就是虛擬機(jī)的基石。

如圖所示:

各種語言都可以在 JVM 上運(yùn)行

從上圖可以看出,虛擬機(jī)不拘泥于 Java 語言,任何一個源文件只要能編譯成 Class 文件的格式,就可以在JVM 上運(yùn)行!Class 文件格式就像是一個接口,只要遵守這個接口,就能夠在 JVM 上運(yùn)行。

2.2 類加載器的工作流程

Class 文件通常是以文件的方式存在(任何二進(jìn)制流都可以是 Class 類型),但只有能被 JVM 加載后才能被使用,才能運(yùn)行編譯后的代碼。系統(tǒng)裝在 Class 類型可以分為加載,鏈接和初始化三個步驟。其中,鏈接也可分為驗證,準(zhǔn)備和解析3步驟。如圖所示:

Class 文件轉(zhuǎn)載過程

2.3 類裝載的條件

JVM 不會無故裝載 Class 文件,只有在必要的時候才裝載,哪幾個時候呢?

  1. 當(dāng)創(chuàng)建一個類的實例是,比如使用 new 關(guān)鍵字,或者通過反射,克隆,反序列化。
  2. 當(dāng)調(diào)用類的靜態(tài)方法時,即當(dāng)使用字節(jié)碼 invokstatic 指令。
  3. 當(dāng)使用類或接口的靜態(tài)字段時(final 常量除外),比如,使用 getstatic 或者 pustatic 指令。
  4. 當(dāng)時用 Java.lang.reflect 包中的方法反射類的方法時。
  5. 當(dāng)初始化子類,要求先初始化父類。
  6. 作為啟動虛擬機(jī),含有 main()方法的那個類。

以上6種情況屬于主動調(diào)用,主動調(diào)用會觸發(fā)初始化,還有一種情況是被動調(diào)用,則不會引起初始化。

2.4 類加載器的雙親委派模型

先來看一個著名的圖:

類加載器雙親委派模型

虛擬機(jī)為了保護(hù)應(yīng)用程序內(nèi)出現(xiàn)多個類名相同的類對象,因此發(fā)明了這個機(jī)制:當(dāng) JVM 需要適用一個類時,在判斷類是否已經(jīng)被加載時,會先從當(dāng)前底層類加載器進(jìn)行判斷。當(dāng)系統(tǒng)需要加載一個類時,會從頂層類開始加載,依次向下嘗試,知道成功,否則拋出ClassNotFound 異常。

# 總結(jié)

這篇文章主要是為了后面的詳細(xì)文章做一個大綱,因此只是講述以 JVM 的一些基本的框架和概念,后面講詳細(xì)的講述內(nèi)部細(xì)節(jié)。讓我們學(xué)習(xí)虛擬機(jī)更加的有條理。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方,同時不同JDK版本的...
    高廣超閱讀 16,051評論 3 83
  • JVM內(nèi)存模型Java虛擬機(jī)(Java Virtual Machine=JVM)的內(nèi)存空間分為五個部分,分別是: ...
    光劍書架上的書閱讀 2,775評論 2 26
  • 介紹JVM中7個區(qū)域,然后把每個區(qū)域可能造成內(nèi)存的溢出的情況說明 程序計數(shù)器:看做當(dāng)前線程所執(zhí)行的字節(jié)碼行號指示器...
    jemmm閱讀 2,305評論 0 9
  • 第一,擁有責(zé)任感。窮人家的孩子早當(dāng)家,窮人家的孩子實在是沒有別的辦法和選擇,所以不得不背負(fù)家庭重?fù)?dān)。真是在背負(fù)責(zé)任...
    shandow閱讀 787評論 0 2
  • “唉,你們聽說了沒?冷茉就快要結(jié)婚了。所以,這次才沒能來。”同學(xué)A無比八卦的說著。 “啊~我的女神??!你怎么能那么...
    貪看年少閱讀 1,274評論 0 1

友情鏈接更多精彩內(nèi)容