這里給大家介紹一下Java虛擬機(jī),這也并不是三言兩語(yǔ)能夠介紹完的,,因此開(kāi)了Java虛擬機(jī)系列,,這一篇文章我們來(lái)學(xué)習(xí)Java虛擬機(jī)的結(jié)構(gòu)原理與運(yùn)行時(shí)數(shù)據(jù)區(qū)域,。 1.Java虛擬機(jī)概述 Oracle官方定義的Java技術(shù)體系主要包括以下幾個(gè)部分:
可以把Java程序設(shè)計(jì)語(yǔ)言,、Java虛擬機(jī)和Java API類庫(kù)這三部分統(tǒng)稱為JDK(Java Development Kit),它是Java程序開(kāi)發(fā)的最小環(huán)境,。另外,,Java API中的Java SE API子集和Java虛擬機(jī)這兩部分統(tǒng)稱為JRE(Java Runtime Environment),它是Java程序運(yùn)行的標(biāo)準(zhǔn)環(huán)境,。 從上面可以看出Java虛擬機(jī)及其重要,,它是整個(gè)Java平臺(tái)的基石,是Java語(yǔ)言編譯代碼的運(yùn)行平臺(tái),。你可以把Java虛擬機(jī)看做一個(gè)抽象的計(jì)算機(jī),,它有各種指令集和各種運(yùn)行時(shí)數(shù)據(jù)區(qū)域。 1.1 Java虛擬機(jī)家族 很多同學(xué)可能認(rèn)為Java虛擬機(jī),,就是一個(gè)虛擬機(jī)而已,,它還有家族?或者認(rèn)為Java虛擬機(jī)指的就是Oracle的HotSpot虛擬機(jī),。這里來(lái)簡(jiǎn)單介紹Java虛擬機(jī)家族,,自從1996年Sun公司發(fā)布的JDK1.0中包含的Sun Classic VM到今天,出現(xiàn)和消亡了很多種虛擬機(jī),,我們這里只簡(jiǎn)單介紹目前存活的相對(duì)主流Java虛擬機(jī),。 HotSpot VM Oracle JDK和OpenJDK中自帶的虛擬機(jī),是最主流的和使用范圍最廣的Java虛擬機(jī),。介紹Java虛擬機(jī)的技術(shù)文章,,如果不做特殊說(shuō)明,大部分都是介紹HotSpot VM的,。HotSpot VM并非是Sun公司開(kāi)發(fā)的,,而是由Longview Technologies這家小公司設(shè)計(jì)的,它在1997年被Sun公司收購(gòu),,Sun公司又在2009年被Oracle收購(gòu),。 J9 VM J9 VM 是IBM開(kāi)發(fā)的VM,目前是其主力發(fā)展的Java虛擬機(jī),。J9 VM的市場(chǎng)定位和HotSpot VM接近,,它是一款設(shè)計(jì)上從服務(wù)端到桌面應(yīng)用再到嵌入式都考慮到的多用途虛擬機(jī),目前J9 VM的性能水平大致跟HotSpot VM是一個(gè)檔次的,。 Zing VM 以Oracle的HotSpot VM為基礎(chǔ),,改進(jìn)了許多會(huì)影響延遲的細(xì)節(jié),。最大的三個(gè)賣點(diǎn)是:
1.2 Java虛擬機(jī)執(zhí)行流程 當(dāng)我們執(zhí)行一個(gè)Java程序時(shí),,它的執(zhí)行流程是怎樣的呢,?如下圖所示。 了解更多Java知識(shí),,獲取原視頻,,源碼,學(xué)習(xí)交流,,那就加入小編的學(xué)習(xí)交流群吧,!616 959 444 從上圖可以看到Java虛擬機(jī)與java語(yǔ)言沒(méi)有什么必然聯(lián)系,它只與特定的二進(jìn)制文件:Class文件有關(guān),。 2.Java虛擬機(jī)結(jié)構(gòu) 這里所講的體系結(jié)構(gòu),,是指的Java虛擬機(jī)的抽象行為,而不是具體的比如HotSpot VM的實(shí)現(xiàn),。按照J(rèn)ava虛擬機(jī)規(guī)范,,抽象的Java虛擬機(jī)如下圖所示。 2.1 Class文件格式 Java文件被編譯后生成了Class文件,,這種二進(jìn)制格式文件不依賴于特定的硬件和操作系統(tǒng),。每一個(gè)Class文件中都對(duì)應(yīng)著唯一一個(gè)類或者接口的的定義信息,但是類或者接口并不一定定義在文件中,,比如類和接口可以通過(guò)類加載器來(lái)直接生成,。 ClassFile的文件結(jié)構(gòu)如下所示。 ClassFile { 2.2 類加載器子系統(tǒng) 類加載器子系統(tǒng)通過(guò)多種類加載器來(lái)查找和加載Class文件到 Java 虛擬機(jī)中,。Java虛擬機(jī)有兩種類加載器:系統(tǒng)加載器和用戶自定義加載器,。其中系統(tǒng)加載器包括以下三種:
用戶自定義加載器,,則是通過(guò)繼承 java.lang.ClassLoader類的方式來(lái)實(shí)現(xiàn)自己的類加載器。 類加載器子系統(tǒng)除了要加載Class文件類到 Java 虛擬機(jī)中,,還必須負(fù)責(zé)驗(yàn)證被導(dǎo)入的Class類的正確性,,為類變量分配并初始化內(nèi)存,以及幫助解析符號(hào)引用,。這些動(dòng)作必須嚴(yán)格按以下順序進(jìn)行: 1.裝載:查找并加載Class文件,。 2.鏈接:驗(yàn)證、準(zhǔn)備,、以及解析,。
3.初始化:將類變量初始化為正確初始值,。 2.3 數(shù)據(jù)類型 Java虛擬機(jī)與Java語(yǔ)言的數(shù)據(jù)類型相似,,可以分為兩類:基本類型和引用類型。Java虛擬機(jī)希望編譯器在編譯期間盡可能的完成類型檢查,,使得虛擬機(jī)在運(yùn)行期間無(wú)需進(jìn)行類型檢查操作,。 2.4 運(yùn)行時(shí)數(shù)據(jù)區(qū)域 很多人將Java的內(nèi)存分為堆內(nèi)存(heap)和棧內(nèi)存(Stack),這種分發(fā)不夠準(zhǔn)確,Java的內(nèi)存區(qū)域劃分實(shí)際上遠(yuǎn)比這復(fù)雜,。 Java虛擬機(jī)在執(zhí)行Java程序的過(guò)程中會(huì)把它所管理的內(nèi)存劃分為不同的數(shù)據(jù)區(qū)域,,根據(jù)《Java虛擬機(jī)規(guī)范(Java SE7版)》的規(guī)定,這些數(shù)據(jù)區(qū)域分別為程序計(jì)數(shù)器,、Java虛擬機(jī)棧,、本地方法棧、Java堆和方法區(qū),,下面我們來(lái)一一的對(duì)它們進(jìn)行介紹,。 2.4.1 程序計(jì)數(shù)器 為了保證程序能夠連續(xù)地執(zhí)行下去,處理器必須具有某些手段來(lái)確定下一條指令的地址,,而程序計(jì)數(shù)器正是起到這種作用,。了解更多Java知識(shí),獲取原視頻,,源碼,,學(xué)習(xí)交流,那就加入小編的學(xué)習(xí)交流群吧,!616 959 444 程序計(jì)數(shù)器(Program Counter Register)也叫做PC寄存器,,是一塊較小的內(nèi)存空間。在虛擬機(jī)概念模型中,,字節(jié)碼解釋器工作時(shí)就是通過(guò)改變程序計(jì)數(shù)器來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令,,Java虛擬機(jī)的多線程是通過(guò)輪流切換并分配處理器執(zhí)行時(shí)間的方式來(lái)實(shí)現(xiàn)的,在一個(gè)確定的時(shí)刻只有一個(gè)處理器執(zhí)行一條線程中的指令,,為了在線程切換后能恢復(fù)到正確的執(zhí)行位置,,每個(gè)線程都會(huì)有一個(gè)獨(dú)立的程序計(jì)數(shù)器,因此,,程序計(jì)數(shù)器是線程私有的,。如果線程執(zhí)行的方法不是Native方法,則程序計(jì)數(shù)器保存正在執(zhí)行的字節(jié)碼指令地址,,如果是Native方法則程序計(jì)數(shù)器的值則為空(Undefined),。程序計(jì)數(shù)器是Java虛擬機(jī)規(guī)范中唯一沒(méi)有規(guī)定任何OutOfMemoryError情況的數(shù)據(jù)區(qū)域。 2.4.2 Java虛擬機(jī)棧 每一條Java虛擬機(jī)線程都有一個(gè)線程私有的Java虛擬機(jī)棧(Java Virtual Machine Stacks),。它的生命周期與線程相同,,與線程是同時(shí)創(chuàng)建的。Java虛擬機(jī)棧存儲(chǔ)線程中Java方法調(diào)用的狀態(tài),,包括局部變量,、參數(shù)、返回值以及運(yùn)算的中間結(jié)果等,。一個(gè)Java虛擬機(jī)棧包含了多個(gè)棧幀,,一個(gè)棧幀用來(lái)存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接,、方法出口等信息,。當(dāng)線程調(diào)用一個(gè)Java方法時(shí),虛擬機(jī)壓入一個(gè)新的棧幀到該線程的Java棧中,,當(dāng)該方法執(zhí)行完成,,這個(gè)棧幀就從Java棧中彈出,。我們平常所說(shuō)的棧內(nèi)存(Stack)指的就是Java虛擬機(jī)棧,。 Java虛擬機(jī)規(guī)范中定義了兩種異常情況:
2.4.3 本地方法棧 Java虛擬機(jī)實(shí)現(xiàn)可能要用到C Stacks來(lái)支持Native語(yǔ)言,,這個(gè)C Stacks就是本地方法棧(Native Method Stack),。它與Java虛擬機(jī)棧類似,只不過(guò)本地方法棧是用來(lái)支持Native方法服務(wù),。如果Java虛擬機(jī)不支持Native方法,,并且也不依賴于C Stacks,可以無(wú)需支持本地方法棧,。在Java虛擬機(jī)規(guī)范中對(duì)本地方法棧的語(yǔ)言和數(shù)據(jù)結(jié)構(gòu)等沒(méi)有強(qiáng)制規(guī)定,,因此具體的Java虛擬機(jī)可以自由實(shí)現(xiàn)它,比如HotSpot VM將本地方法棧和Java虛擬機(jī)棧合二為一,。 與Java虛擬機(jī)棧類似,,本地方法棧也會(huì)拋出 StackOverflowError和OutOfMemoryError異常 2.4.4 Java堆 Java堆(Java Heap)是被所有線程共享的運(yùn)行時(shí)內(nèi)存區(qū)域。Java堆用來(lái)存放對(duì)象實(shí)例,,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存,。Java堆存儲(chǔ)的對(duì)象被垃圾收集器管理,這些受管理的對(duì)象無(wú)需也無(wú)法顯示的銷毀,。從內(nèi)存回收的角度,,Java堆可以粗略的分為新生代和老年代。從內(nèi)存分配的角度Java堆中可能劃分出多個(gè)線程私有的分配緩沖區(qū),。不管如何劃分,,Java堆存儲(chǔ)的內(nèi)容是不變的,進(jìn)行劃分是為了能更快的回收或者分配內(nèi)存,。 Java堆的容量可以時(shí)固定的,,也可以動(dòng)態(tài)的擴(kuò)展。Java堆的所使用的內(nèi)存在物理上不需要連續(xù),邏輯上連續(xù)即可,。 Java虛擬機(jī)規(guī)范中定義了一種異常情況:
2.4.5 方法區(qū) 方法區(qū)(Method Area)是被所有線程共享的運(yùn)行時(shí)內(nèi)存區(qū)域,。用來(lái)存儲(chǔ)已經(jīng)被Java虛擬機(jī)加載的類的結(jié)構(gòu)信息,包括: 運(yùn)行時(shí)常量池,、字段和方法信息,、靜態(tài)變量等數(shù)據(jù)。方法區(qū)是Java堆的邏輯組成部分,,它一樣在物理上不需要連續(xù),,并且可以選擇在方法區(qū)中不實(shí)現(xiàn)垃圾收集。方法區(qū)并不等同于永久代,,只是因?yàn)?span>HotSpot VM使用永久代來(lái)實(shí)現(xiàn)方法區(qū),,對(duì)于其他的Java虛擬機(jī),比如J9和JRockit等,,并不存在永久代概念,。 Java虛擬機(jī)規(guī)范中定義了一種異常情況:
運(yùn)行時(shí)常量池 運(yùn)行時(shí)常量池(Runtime Constant Pool)是方法區(qū)的一部分,。在2.1 Class文件格式這一小節(jié)中我們得知,Class文件不僅包含了類的版本,、接口,、字段和方法等信息,還包含了常量池,,它用來(lái)存放編譯時(shí)期生成的字面量和符號(hào)引用,,這些內(nèi)容會(huì)在類加載后存放在方法區(qū)的運(yùn)行時(shí)常量池中。運(yùn)行時(shí)常量池可以理解為是類或接口的常量池的運(yùn)行時(shí)表現(xiàn)形式,。了解更多Java知識(shí),,獲取原視頻,源碼,,學(xué)習(xí)交流,,那就加入小編的學(xué)習(xí)交流群吧!616 959 444 Java虛擬機(jī)規(guī)范中定義了一種異常情況: 當(dāng)創(chuàng)建類或接口時(shí),,如果構(gòu)造運(yùn)行時(shí)常量池所需的內(nèi)存超過(guò)了方法區(qū)所能提供的最大值,,Java虛擬機(jī)會(huì)拋出OutOfMemoryError異常。 |
|
來(lái)自: timtxu > 《時(shí)尚科技》