自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java是怎么運(yùn)行起來的?深入理解Java虛擬機(jī)

開發(fā)
了解JVM是如何支持Java語言和其他相關(guān)語言的,對于程序員來說是很有裨益的。本文分享一下Java的工作原理和JVM的內(nèi)部結(jié)構(gòu)。

Java虛擬機(jī)(JVM)是一個(gè)運(yùn)行時(shí)環(huán)境,可以執(zhí)行用Java編程語言編寫的程序。Java語言是一種高級(jí)語言,它通過抽象和封裝的機(jī)制,讓開發(fā)者可以專注于業(yè)務(wù)邏輯和功能實(shí)現(xiàn),而不用關(guān)心底層的細(xì)節(jié)。因此,運(yùn)行/開發(fā)Java程序時(shí),不必深入了解Java程序的執(zhí)行過程或JVM的內(nèi)部原理。對于大多數(shù)開發(fā)者來說,JVM就像一個(gè)神奇的盒子,能夠幫助他們實(shí)現(xiàn)功能和完成任務(wù)。

但是,了解JVM是如何支持Java語言和其他相關(guān)語言的,對于程序員來說是很有裨益的!

本文分享一下Java的工作原理和JVM的內(nèi)部結(jié)構(gòu)。

1. Java虛擬機(jī)

Java虛擬機(jī)(JVM)是一個(gè)抽象的機(jī)器,用來執(zhí)行一種代碼,即bytecode。你可以把它看作是我們的代碼和計(jì)算機(jī)硬件之間的橋梁,它把我們的代碼作為輸入,轉(zhuǎn)換成字節(jié)碼并在計(jì)算機(jī)硬件上運(yùn)行它,從而實(shí)現(xiàn)開發(fā)者預(yù)期的結(jié)果。

2. 字節(jié)碼 (bytecode)

字節(jié)碼是一種JVM能夠理解的文件類型。它是通過compilingJava代碼(使用javac)生成的一種Java程序的中間表示形式。它之所以叫字節(jié)碼,是因?yàn)槊總€(gè)操作碼(operation)都是單字節(jié)大小的。字節(jié)碼可以再次編譯成機(jī)器碼并在計(jì)算機(jī)上運(yùn)行。

3. 編譯

運(yùn)行Java程序的第一步是編譯。如果你有一個(gè)單獨(dú)的Java文件,你可以使用提供的命令行工具javac來觸發(fā)編譯。

javac HelloWorld.java

圖片

上面代碼會(huì)把一個(gè)給定的Java文件編譯成.class文件,其中包含bytecode。如果源代碼有錯(cuò)誤,編譯會(huì)失敗并報(bào)出編譯錯(cuò)誤。

你可以使用提供的工具javap來查看已創(chuàng)建的類文件,以了解類文件的內(nèi)部情況。

javap HelloWorld.class

4. 執(zhí)行

在通過編譯創(chuàng)建了.class文件之后,可以使用java語法來啟動(dòng)一個(gè)JVM的實(shí)例,它會(huì)觸發(fā)一個(gè)包含多個(gè)復(fù)雜步驟的執(zhí)行路徑,最終執(zhí)行我們提供的代碼。

java HelloWorld

首先JVM需要獲取.class文件,并將它加載到JVM的內(nèi)存區(qū)域中。這個(gè)初始過程是通過JVM類加載器來實(shí)現(xiàn)的。

5. 什么是類加載?

抽象地說,類加載就是掃描并遍歷提供的.class文件,并將類文件中的內(nèi)容加載到JVM的內(nèi)存區(qū)域中。然后,執(zhí)行引擎就可以引用這些存儲(chǔ)的數(shù)據(jù),繼續(xù)執(zhí)行我們的代碼。

JVM中有三種類型的類加載器,分別是:

  • 引導(dǎo)類加載器
  • 擴(kuò)展類加載器
  • 應(yīng)用類加載器

引導(dǎo)類加載器的職責(zé)是加載基礎(chǔ)/核心的Java類,這些類對于Java程序運(yùn)行是必不可少的。在早期的Java版本中,這些核心類被包含在位于jre/lib目錄下的rt.jar文件中,但在后來的Java版本中,rt.jar中的內(nèi)容被分割成模塊化的組件。

擴(kuò)展類加載器的職責(zé)是加載lib/ext目錄下的類,這些類可能包括我們在代碼中使用的任何擴(kuò)展。

應(yīng)用類加載器是三種中最常用的一種,它負(fù)責(zé)加載用戶定義的類。它會(huì)掃描我們程序的類路徑,并加載其中的類。

6. 類加載過程

類加載過程有兩個(gè)主要步驟:

  • 加載
  • 鏈接

7. 加載

在加載過程中,類加載器讀取類文件的二進(jìn)制表示形式,即.class文件,并在JVM的運(yùn)行時(shí)內(nèi)存中創(chuàng)建它的表示。這個(gè)表示稱為Class Object,它位于JVM內(nèi)存的方法區(qū)中。

8. 鏈接

在加載過程之后,開始鏈接。鏈接有三個(gè)步驟。

  • 驗(yàn)證 — 確保類文件的正確性。驗(yàn)證類是否符合Java規(guī)范。
  • 準(zhǔn)備 — 為靜態(tài)塊/字段分配內(nèi)存,并為靜態(tài)變量賦予默認(rèn)值(不是初始值?。?/li>
  • 解析 — 解析類文件中的(符號(hào))引用。

解析:

在鏈接的解析階段,類加載器會(huì)解析常量池表,這是一個(gè)位于.class文件/類對象中的實(shí)體,類似于一個(gè)符號(hào)表,指定了類中的字段/方法/引用。在類文件中,對其他類的引用是以符號(hào)方式表示的,沒有具體的內(nèi)存地址來引用。解析會(huì)搜索JVM內(nèi)存,并為那些符號(hào)引用分配具體的引用。如果在.class文件中發(fā)現(xiàn)了一個(gè)尚未加載的類,它會(huì)觸發(fā)該類本身的加載/鏈接過程,這可能會(huì)導(dǎo)致一個(gè)遞歸的加載和鏈接過程。

在字節(jié)碼加載和鏈接之后,類就成功地存儲(chǔ)在JVM內(nèi)存中(將在后面的部分討論),并準(zhǔn)備好初始化。

9. 初始化

當(dāng)代碼中第一次用new關(guān)鍵字或靜態(tài)字段來引用一個(gè)類,或者當(dāng)程序執(zhí)行時(shí)遇到一個(gè)初始化類(比如Main類),則會(huì)觸發(fā)類文件的初始化。

在初始化階段,執(zhí)行靜態(tài)塊,靜態(tài)變量被分配初始值。

10. 運(yùn)行時(shí)內(nèi)存區(qū)域

在上面的段落中,多次提到了將類文件數(shù)據(jù)存儲(chǔ)在JVM內(nèi)存中。這些數(shù)據(jù)究竟存儲(chǔ)在哪里,來作為加載/鏈接/初始化的結(jié)果?答案是運(yùn)行時(shí)內(nèi)存區(qū)域。

JVM運(yùn)行時(shí)內(nèi)存區(qū)域是指定的內(nèi)存空間,它被劃分為多個(gè)部分,用于存儲(chǔ)執(zhí)行相關(guān)/類文件相關(guān)的數(shù)據(jù)。

運(yùn)行時(shí)內(nèi)存區(qū)的主要區(qū)域如下:

(1) 方法區(qū)

方法區(qū)是運(yùn)行時(shí)內(nèi)存的一部分,用于存儲(chǔ)與類文件相關(guān)的數(shù)據(jù)。運(yùn)行時(shí)常量池、字段元數(shù)據(jù)、類元數(shù)據(jù)、方法元數(shù)據(jù)和字節(jié)碼本身等都存儲(chǔ)在方法區(qū)中。

(2) 程序計(jì)數(shù)器(PC)

程序計(jì)數(shù)器是一個(gè)小的內(nèi)存區(qū)域,用于存儲(chǔ)當(dāng)前正在執(zhí)行的操作的地址,這是Java程序執(zhí)行的必要信息。每個(gè)線程都有自己的PC。

(3) 堆

存儲(chǔ)所有的類/數(shù)組實(shí)例,是所有線程共享的一塊內(nèi)存。

(4) JVM棧

保存局部變量和部分結(jié)果。包含棧幀。每個(gè)線程都有自己的JVM棧。

11. 棧幀

當(dāng)一個(gè)方法被調(diào)用時(shí),在棧中創(chuàng)建一個(gè)新的幀。它會(huì)存儲(chǔ)與該方法相關(guān)的局部變量和部分結(jié)果。如果在該方法內(nèi)部調(diào)用了另一個(gè)方法,就會(huì)為新調(diào)用的方法創(chuàng)建一個(gè)新的棧幀。在給定線程中,一次只有一個(gè)幀是活動(dòng)的。

12. 執(zhí)行

在上面的部分中,簡要地介紹了Java源代碼是如何編譯并加載到JVM運(yùn)行時(shí)內(nèi)存區(qū)域中的。

接下來看看這些數(shù)據(jù)是如何執(zhí)行的。

這部分過程是通過JVM的執(zhí)行引擎來實(shí)現(xiàn)的,它由兩個(gè)主要部分組成:(執(zhí)行引擎還包括許多其他組件,但在本文中不會(huì)提及。)

  • 解釋器
  • JIT(即時(shí))編譯器

“Java作為一種編程語言,是一種混合的解釋和編譯語言,也就是說Java代碼既要經(jīng)過編譯,又要經(jīng)過解釋。簡單來說,當(dāng)類文件開始運(yùn)行時(shí),JVM會(huì)先用解釋器直接執(zhí)行字節(jié)碼,不需要編譯。這樣做的主要好處是可以提高啟動(dòng)速度和執(zhí)行速度(不用等待編譯過程)。

在解釋的過程中,JVM會(huì)發(fā)現(xiàn)代碼中的熱點(diǎn)和熱區(qū),也就是經(jīng)常執(zhí)行或者可以優(yōu)化的代碼段。這些代碼段會(huì)被JIT編譯器編譯成本地代碼,然后執(zhí)行引擎會(huì)從解釋模式切換到執(zhí)行模式?!?/p>

這個(gè)編譯過程有多個(gè)層次,稱為分層編譯。

責(zé)任編輯:趙寧寧 來源: Java學(xué)研大本營
相關(guān)推薦

2012-11-14 09:57:46

JavaJava虛擬機(jī)JVM

2019-07-24 16:04:47

Java虛擬機(jī)并發(fā)

2024-03-29 11:42:21

Java虛擬機(jī)

2024-04-03 13:49:00

Java虛擬機(jī)方法區(qū)

2016-09-01 12:37:13

OpenStack虛擬機(jī)Metadata

2024-03-26 07:30:07

Java虛擬機(jī)源文件

2024-04-10 07:40:45

Java虛擬機(jī)內(nèi)存

2019-12-31 10:45:30

JavaVisualVM高并發(fā)

2011-12-28 13:24:47

JavaJVM

2011-12-28 13:38:00

JavaJVM

2012-03-05 11:09:01

JavaClass

2018-07-09 15:11:14

Java逃逸JVM

2022-07-06 08:05:52

Java對象JVM

2010-03-12 08:55:06

Java內(nèi)省反射

2023-09-19 22:47:39

Java內(nèi)存

2009-06-19 14:10:42

Java多態(tài)性

2012-01-18 11:24:18

Java

2024-12-31 09:00:12

Java線程狀態(tài)

2010-03-15 14:24:59

StackHeapJVM

2022-08-21 16:52:27

Linux虛擬內(nèi)存
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)