JAVA虛擬機(jī)(JVM)一:了解JAVA體系結(jié)構(gòu)


JAVA虛擬機(jī)(JVM)系列:
JAVA虛擬機(jī)(JVM)一:了解JAVA體系結(jié)構(gòu)
JAVA虛擬機(jī)(JVM)二:JVM工作原理
JAVA虛擬機(jī)(JVM)三:類加載器子系統(tǒng)
JAVA虛擬機(jī)(JVM)四:JMM(Java內(nèi)存模型)
JAVA虛擬機(jī)(JVM)五:JVM執(zhí)行引擎
……

JAVA虛擬機(jī)(JVM)實(shí)戰(zhàn)一:Docker容器環(huán)境下編譯OpenJDK11


一、前言

大家都知道,Java語言的一個(gè)非常重要的特點(diǎn)就是與平臺的無關(guān)性。而使用Java虛擬機(jī)是實(shí)現(xiàn)這一特點(diǎn)的關(guān)鍵。一般的高級語言如果要在不同的平臺上運(yùn)行,至少需要編譯成不同的目標(biāo)代碼。而引入Java語言虛擬機(jī)后,Java語言在不同平臺上運(yùn)行時(shí)不需要重新編譯。Java語言使用Java虛擬機(jī)屏蔽了與具體平臺相關(guān)的信息,使得Java語言編譯程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運(yùn)行。Java虛擬機(jī)在執(zhí)行字節(jié)碼時(shí),把字節(jié)碼解釋成具體平臺上的機(jī)器指令執(zhí)行。這就是Java的能夠“一次編譯,到處運(yùn)行”的原因。

JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫,JVM是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來的計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的。

所以,JVM是JAVA的重中之重,作為一個(gè)JAVA系的開發(fā)者,必須要對JVM有深刻的理解,才能寫出高效的JAVA程序。故本人一直想對JVM做一次深入的學(xué)習(xí),那么現(xiàn)在就開始吧。

前提:本文講的基本都是以Sun HotSpot虛擬機(jī)為基礎(chǔ)的

本節(jié)是為寫一系列JVM文章做準(zhǔn)備,因?yàn)?,講JVM之前必須要學(xué)習(xí)了解JAVA的體系結(jié)構(gòu),才能搞清楚前因后果,來龍去脈。只有這樣體系的學(xué)習(xí),才是有效的學(xué)習(xí)方法,否則肯定是一知半解,理解不透徹,說不定看完的就忘記了。

很多人都在用Java,但對Java的體系結(jié)構(gòu)并不是很了解,最近也是想了解JVM的相關(guān)知識,才開始關(guān)注這方面的內(nèi)容,做了一些筆記,摘抄給大家共同學(xué)習(xí)。

二、JAVA體系結(jié)構(gòu)

說起Java,人們首先想到的是Java編程語言,然而事實(shí)上,Java是一種技術(shù),它由四方面組成:

Java編程語言、
Java類文件格式、
Java虛擬機(jī)
Java應(yīng)用程序接口(Java API)。

它們的關(guān)系如下圖所示:


JAVA體系結(jié)構(gòu).png

運(yùn)行期環(huán)境代表著Java平臺,開發(fā)人員編寫Java代碼(.java文件),然后將之編譯成字節(jié)碼(.class文件),再然后字節(jié)碼被裝入內(nèi)存,一旦字節(jié)碼進(jìn)入虛擬機(jī),它就會被解釋器解釋執(zhí)行,或者是被即時(shí)代碼發(fā)生器有選擇的轉(zhuǎn)換成機(jī)器碼執(zhí)行。

Java平臺由Java虛擬機(jī)和Java應(yīng)用程序接口搭建,Java語言則是進(jìn)入這個(gè)平臺的通道,用Java語言編寫并編譯的程序可以運(yùn)行在這個(gè)平臺上。這個(gè)平臺的結(jié)構(gòu)如下圖所示:

JAVA平臺結(jié)構(gòu).png

在Java平臺的結(jié)構(gòu)中, 可以看出,Java虛擬機(jī)(JVM) 處在核心的位置,是程序與底層操作系統(tǒng)和硬件無關(guān)的關(guān)鍵。它的下方是移植接口,移植接口由兩部分組成:適配器和Java操作系統(tǒng), 其中依賴于平臺的部分稱為適配器;JVM 通過移植接口在具體的平臺和操作系統(tǒng)上實(shí)現(xiàn);在JVM 的上方是Java的基本類庫和擴(kuò)展類庫以及它們的API, 利用Java API編寫的應(yīng)用程序(application) 和小程序(Java applet) 可以在任何Java平臺上運(yùn)行而無需考慮底層平臺, 就是因?yàn)橛蠮ava虛擬機(jī)(JVM)實(shí)現(xiàn)了程序與操作系統(tǒng)的分離,從而實(shí)現(xiàn)了Java 的平臺無關(guān)性。

JVM在它的生存周期中有一個(gè)明確的任務(wù),那就是運(yùn)行Java程序,因此當(dāng)Java程序啟動(dòng)的時(shí)候,就產(chǎn)生JVM的一個(gè)實(shí)例;當(dāng)程序運(yùn)行結(jié)束的時(shí)候,該實(shí)例也跟著消失了。

三、一些JAVA基本概念

既然JVM那么重要,下面我們降深入的研究JVM,弄懂它的工作原理。但,此前,我們很有必要先了解一些JAVA的基本概念。

1、什么是JVM

JVM是Java Virtual Machine(Java虛擬機(jī))的縮寫,JVM是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來的計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的。Java虛擬機(jī)包括一套字節(jié)碼指令集、一組寄存器、一個(gè)棧、一個(gè)垃圾回收堆和一個(gè)存儲方法域。 JVM屏蔽了與具體操作系統(tǒng)平臺相關(guān)的信息,使Java程序只需生成在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(字節(jié)碼),就可以在多種平臺上不加修改地運(yùn)行。JVM在執(zhí)行字節(jié)碼時(shí),實(shí)際上最終還是把字節(jié)碼解釋成具體平臺上的機(jī)器指令執(zhí)行。

2、JRE/JDK/JVM是什么關(guān)系

JRE(JavaRuntimeEnvironment,Java運(yùn)行環(huán)境),也就是Java平臺。所有的Java 程序都要在JRE下才能運(yùn)行。普通用戶只需要運(yùn)行已開發(fā)好的java程序,安裝JRE即可。

JDK(Java Development Kit):是程序開發(fā)者用來來編譯、調(diào)試java程序用的開發(fā)工具包。JDK的工具也是Java程序,也需要JRE才能運(yùn)行。為了保持JDK的獨(dú)立性和完整性,在JDK的安裝過程中,JRE也是 安裝的一部分。所以,在JDK的安裝目錄下有一個(gè)名為jre的目錄,用于存放JRE文件。

JVM(JavaVirtualMachine,Java虛擬機(jī)):是JRE的一部分。它是一個(gè)虛構(gòu)出來的計(jì)算機(jī),是通過在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來實(shí)現(xiàn)的。JVM有自己完善的硬件架構(gòu),如處理器、堆棧、寄存器等,還具有相應(yīng)的指令系統(tǒng)。Java語言最重要的特點(diǎn)就是跨平臺運(yùn)行。使用JVM就是為了支持與操作系統(tǒng)無關(guān),實(shí)現(xiàn)跨平臺。

3、數(shù)據(jù)類型

Java虛擬機(jī)中,數(shù)據(jù)類型可以分為兩類:

primitive types(原生類型)
reference types(引用類型)

3.1 primitive types(原生類型)

primitive types(原生類型),保存原始值,即:他代表的值就是數(shù)值本身。

原生類型包括:

Numeric Types(數(shù)值類型)

byte(1 byte)
short,char(2 bytes)
int,float(4 bytes)
long,double(8 bytes)

Boolean Type(布爾類型)

boolean(1 byte)

returnAddress 類型

returnAddress 類型

returnAddress 類型的值是指向字節(jié)碼的指針。

不管是物理機(jī)還是虛擬機(jī),運(yùn)行時(shí)內(nèi)存中的數(shù)據(jù)總歸可分為兩類:代碼,數(shù)據(jù)。對于 JVM 來說,程序就是存儲在方法區(qū)的字節(jié)碼指令,而 returnAddress 類型的值就是指向特定指令內(nèi)存地址的指針。

JVM支持多線程,每個(gè)線程有自己的程序計(jì)數(shù)器(pc register),而 pc 中的值就是當(dāng)前指令所在的內(nèi)存地址,即 returnAddress 類型的數(shù)據(jù),當(dāng)線程執(zhí)行 native 方法時(shí),pc 中的值為 undefined。

3.2 reference types(引用類型)

reference types(引用類型),讓 JVM 能更好的支持于面向?qū)ο笳Z言的設(shè)計(jì),它存儲的是存引用值,引用值用來指向內(nèi)存中分配的類實(shí)例或者數(shù)組,而非對象或數(shù)組本身,對象本身存放在這個(gè)引用值所表示的地址的位置。

引用類型包括:

類類型
接口類型
數(shù)組

4、對象引用類型

對象引用類型分為

強(qiáng)引用:就是我們一般聲明對象時(shí)虛擬機(jī)生成的引用,強(qiáng)引用環(huán)境下,垃圾回收時(shí)需要嚴(yán)格判斷當(dāng)前對象是否被強(qiáng)引用,如果被強(qiáng)引用,則不會被垃圾回收。

軟引用:軟引用一般被做為緩存來使用。與強(qiáng)引用的區(qū)別是,軟引用在垃圾回收時(shí),虛擬機(jī)會根據(jù)當(dāng)前系統(tǒng)的剩余內(nèi)存來決定是否對軟引用進(jìn)行回收。如果剩余內(nèi)存比較緊張,則虛擬機(jī)會回收軟引用所引用的空間;如果剩余內(nèi)存相對富裕,則不會進(jìn)行回收。換句話說,虛擬機(jī)在發(fā)生OutOfMemory時(shí),肯定是沒有軟引用存在的。

弱引用:弱引用與軟引用類似,都是作為緩存來使用。但與軟引用不同,弱引用在進(jìn)行垃圾回收時(shí),是一定會被回收掉的,因此其生命周期只存在于一個(gè)垃圾回收周期內(nèi)。

虛引用:顧名思義,就是形同虛設(shè),與其他幾種引用都不同,虛引用并不會決定對象的生命周期。如果一個(gè)對象僅持有虛引用,那么它就和沒有任何引用一樣,在任何時(shí)候都可能被垃圾回收。

強(qiáng)引用不用說,我們系統(tǒng)一般在使用時(shí)都是用的強(qiáng)引用。

軟引用弱引用比較少見,他們一般被作為緩存使用,而且一般是在內(nèi)存大小比較受限的情況下做為緩存。因?yàn)槿绻麅?nèi)存足夠大的話,可以直接使用強(qiáng)引用作為緩存即可,同時(shí)可控性更高。因而,他們常見的是被使用在桌面應(yīng)用系統(tǒng)的緩存。

虛引用主要用來跟蹤對象被垃圾回收的活動(dòng)。

虛引用軟引用弱引用的一個(gè)區(qū)別在于:虛引用必須和引用隊(duì)列(ReferenceQueue)聯(lián)合使用。當(dāng)垃 圾回收器準(zhǔn)備回收一個(gè)對象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會在回收對象的內(nèi)存之前,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過判斷引用隊(duì)列中是 否已經(jīng)加入了虛引用,來了解被引用的對象是否將要被垃圾回收。程序如果發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對象的內(nèi)存被回收之前采取必要的行動(dòng)。

5、堆與棧

是運(yùn)行時(shí)的單位
是存儲的單位。

解決程序的運(yùn)行問題,即程序如何執(zhí)行,或者說如何處理數(shù)據(jù);
解決的是數(shù)據(jù)存儲的問題,即數(shù)據(jù)怎么放、放在哪兒。

在Java中一個(gè)線程就會相應(yīng)有一個(gè)線程棧與之對應(yīng),這點(diǎn)很容易理解,因?yàn)椴煌木€程執(zhí)行邏輯有所不同因此需要一個(gè)獨(dú)立的線程棧。而堆則是所有線程共享的。棧因?yàn)槭沁\(yùn)行單位,因此里面存儲的信息都是跟當(dāng)前線程(或程序)相關(guān)信息的。包括局部變量、程序運(yùn)行狀態(tài)、方法返回值等等;而堆只負(fù)責(zé)存儲對象信息。

堆中存的是對象。棧中存的是基本數(shù)據(jù)類型和堆中對象的引用。

堆和棧中,棧是程序運(yùn)行最根本的東西。程序運(yùn)行可以沒有堆,但是不能沒有棧。而堆是為棧進(jìn)行數(shù)據(jù)存儲服務(wù),說白了堆就是一塊共享的內(nèi)存。不過,正是因?yàn)槎押蜅5姆蛛x的思想,才使得Java的垃圾回收成為可能。

Java中,棧的大小通過-Xss來設(shè)置,當(dāng)棧中存儲數(shù)據(jù)比較多時(shí),需要適當(dāng)調(diào)大這個(gè)值,否則會出現(xiàn)java.lang.StackOverflowError異常。常見的出現(xiàn)這個(gè)異常的是無法返回的遞歸,因?yàn)榇藭r(shí)棧中保存的信息都是方法返回的記錄點(diǎn)。

四、結(jié)語

再來復(fù)習(xí)一下JAVA的系統(tǒng)機(jī)構(gòu)圖,加深印象


JAVA體系結(jié)構(gòu).png

這一節(jié)是為學(xué)習(xí)JVM做準(zhǔn)備的,下面,我們就開始進(jìn)入對正主的學(xué)習(xí),敬請期待。

本人能力有限,這里只局限于本人的認(rèn)知,如有描述不當(dāng)?shù)牡胤?,麻煩諸位指出。

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

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

  • 內(nèi)存溢出和內(nèi)存泄漏的區(qū)別 內(nèi)存溢出:out of memory,是指程序在申請內(nèi)存時(shí),沒有足夠的內(nèi)存空間供其使用,...
    Aimerwhy閱讀 806評論 0 1
  • 《深入理解Java虛擬機(jī)》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,473評論 1 34
  • JAVA虛擬機(jī)的生命周期 一個(gè)運(yùn)行時(shí)的Java虛擬機(jī)實(shí)例的天職是:負(fù)責(zé)運(yùn)行一個(gè)java程序。當(dāng)啟動(dòng)一個(gè)Java程序...
    Solang閱讀 1,226評論 0 19
  • 第二部分 自動(dòng)內(nèi)存管理機(jī)制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運(yùn)行數(shù)據(jù)區(qū)域 程序計(jì)數(shù)器:當(dāng)前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,279評論 0 2
  • 理解Java虛擬機(jī)體系結(jié)構(gòu) 1 概述 眾所周知,Java支持平臺無關(guān)性、安全性和網(wǎng)絡(luò)移動(dòng)性。而Java平臺由Jav...
    蟻前閱讀 879評論 0 51

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