java自從問(wèn)世以來(lái)沙兰,一直號(hào)稱一處編譯,處處運(yùn)行。那么java的底層的是什么樣的呢攻谁?我們所熟知的JDK(Java Development Kit)其實(shí)是一個(gè)很大的東西元媚,包含了JRE(Java Runtime Environment)轧叽,Java 語(yǔ)言以及一些工具集。
一刊棕、 Java 類的加載過(guò)程
(一)炭晒、裝載(Load)
裝載(Loading) 是類加載的一個(gè)階段,需要Java 虛擬機(jī)來(lái)完成以下過(guò)程
1). 通過(guò)一個(gè)類將一個(gè)類的二進(jìn)制文件字節(jié)流讀取進(jìn)JVM中甥角。
2). 將這些二進(jìn)制文件字節(jié)流裝載進(jìn)運(yùn)行時(shí)數(shù)據(jù)區(qū)中网严。
3). 在Java 堆中生成一個(gè)代表這個(gè)java 類的對(duì)象,并把它作為方法區(qū)的數(shù)據(jù)的入口嗤无。
(二)震束、鏈接(Link)
1).驗(yàn)證(Verify)
加載完成后,JVM就會(huì)去驗(yàn)證Class文件的格式当犯,保證Class文件中包含的數(shù)據(jù)格式符合JVM的要求垢村,且不會(huì)對(duì)JVM的自身安全造成影響。
如果您打開(kāi)過(guò)class的二進(jìn)制文件就會(huì)知道前面4字節(jié)是cafe babe 嚎卫,那這個(gè)又代表什么呢嘉栓?通過(guò)下面官方提供的對(duì)照表可以知道,前面四個(gè)字節(jié)就是表明這個(gè)是一個(gè)標(biāo)識(shí)類的文件格式拓诸,U4 代表的是4字節(jié)侵佃,U2代表是2字節(jié),按照這個(gè)對(duì)照表可以知道class二進(jìn)制文件中包含了類的主版本恰响、次版本趣钱、方法、常量池等信息
加載過(guò)程中就會(huì)涉及到j(luò)ava加載機(jī)制-雙親委派機(jī)制
①. 類加載器收到加載請(qǐng)求胚宦;
②. 不會(huì)直接去加載首有,而是委托給其父類加載器去加載 燕垃,直到Bootstrap加載器去加載;
③. 如果父類加載器無(wú)法加載則讓其子類加載器去加載井联;
④. 重復(fù)③卜壕,直到加載完成。
這樣做的一個(gè)好處就是可以避免一個(gè)類在JVM中多次加載烙常,也可以避免JVM自身的類被修改轴捎,保證JVM的自身安全。
主要的JVM加載器
Bootstrap Class Loader : 主要加載 %JAVA_HOME%/jre/lib下java自帶的jar包蚕脏;
Extension Class Loader : 主要加載 %JAVA_HOME%/jre/lib/ext下的jar包或者-Djava.ext.dirs指定目錄下的jar包
Application Class Loader : 主要加載 classpath指定的jar包以及-Djava.class.path指定目錄下的jar包
Custom Class Loader : 是java.lang.ClassLoader的子類自定義的加載類侦副,通常加載自定義的類
2). 準(zhǔn)備(Prepare)
接下來(lái)就是準(zhǔn)備階段了,這一過(guò)程主要是為類的變量分配內(nèi)存并設(shè)置默認(rèn)值驼鞭,這些內(nèi)存都是在方法區(qū)中分配的秦驯。這里只會(huì)分配final、static關(guān)鍵字修飾的變量挣棕,非這些關(guān)鍵字修飾的變量會(huì)在虛擬機(jī)棧中分配译隘。
3). 解析(Resolve)
解析主要是將類中的符號(hào)引用變?yōu)橹苯右茫@里涉及類或接口的解析洛心,字段的解析固耘、類方法的解析、接口方法的解析词身。符號(hào)引用就是以一組符號(hào)的形式表示出一些特定的信息;直接引用就是就是將這些信息轉(zhuǎn)化為內(nèi)存地址或一個(gè)偏移量
(三)厅目、初始化(Initialize)
類或接口的初始化包括執(zhí)行類或接口的初始化方法。Java虛擬機(jī)是多線程的偿枕,所以類或接口的初始化需要同步璧瞬,因?yàn)槠渌恍┚€程可能同時(shí)嘗試初始化同一個(gè)類或接口户辫。還可能遞歸地請(qǐng)求類或接口的初始化渐夸,作為該類或接口初始化的一部分。Java虛擬機(jī)的實(shí)現(xiàn)負(fù)責(zé)通過(guò)以下過(guò)程來(lái)處理同步和遞歸初始化渔欢。它假定Class對(duì)象已經(jīng)進(jìn)行了驗(yàn)證和準(zhǔn)備墓塌,而且Class對(duì)象包含的狀態(tài)指示了以下四種情況之一:
- 對(duì)這個(gè)Class對(duì)象進(jìn)行了驗(yàn)證和準(zhǔn)備,但沒(méi)有初始化奥额。
- 這個(gè)Class對(duì)象是由某個(gè)特定線程初始化的苫幢。
- 這個(gè)Class對(duì)象已經(jīng)完全初始化,可以使用了垫挨。
- 這個(gè)Class對(duì)象處于錯(cuò)誤狀態(tài)韩肝,可能是因?yàn)槌跏蓟瘒L試失敗。
二九榔、JVM 內(nèi)存模型
JVM內(nèi)存模型就是在符合現(xiàn)有內(nèi)存模式的基礎(chǔ)上屏蔽了各種硬件和和操作系統(tǒng)的訪問(wèn)差異的哀峻,保證了Java程序在各種平臺(tái)下對(duì)內(nèi)存的訪問(wèn)都能保證效果一致的機(jī)制及規(guī)范涡相,其主要的運(yùn)行時(shí)數(shù)據(jù)區(qū)處理相關(guān)差異。JVM定義了許多在程序運(yùn)行時(shí)的運(yùn)行數(shù)據(jù)區(qū)剩蟀。一些數(shù)據(jù)區(qū)在隨著JVM生命周期活動(dòng)催蝗,即與JVM的啟動(dòng)停止一致。另一些則和線程的生命周期相同育特,與線程同生共死丙号。
(一)、 方法區(qū)(Method Area)
方法區(qū)是在JVM中是所有線程所共享的缰冤,它存儲(chǔ)每個(gè)類的結(jié)構(gòu)犬缨,例如運(yùn)行時(shí)常量池、字段和方法數(shù)據(jù)棉浸,以及方法和構(gòu)造函數(shù)的代碼遍尺,包括類和實(shí)例初始化和接口初始化中使用的特殊方法。它是隨著JVM的啟動(dòng)而啟動(dòng)的涮拗,在邏輯上方法區(qū)是屬于堆的一部分乾戏,在JVM的規(guī)范中并沒(méi)有強(qiáng)制性的要求方法區(qū)進(jìn)行垃圾回收,而且方法區(qū)的大小可以固定也可以對(duì)其進(jìn)行擴(kuò)展三热,并沒(méi)有要求方法區(qū)的內(nèi)存空間是連續(xù)的鼓择,但是在方法區(qū)內(nèi)存不夠的時(shí)候會(huì)OutOfMemoryError
(二)、堆(Heap)
堆與方法區(qū)一樣是所有線程所共享的就漾,也是隨著JVM的啟動(dòng)而啟動(dòng)呐能,它是為所有類實(shí)例或數(shù)組分配內(nèi)存的運(yùn)行時(shí)數(shù)據(jù)區(qū)域。該區(qū)域中的對(duì)象的堆存儲(chǔ)由垃圾回收機(jī)制回收抑堡。堆可以是固定大小的摆出,也可以根據(jù)計(jì)算的要求進(jìn)行擴(kuò)展,如果沒(méi)有必要使用更大的堆首妖,則可以縮小偎漫。堆的內(nèi)存同樣不需要是連續(xù)的。但是在堆內(nèi)存不夠的時(shí)候會(huì)OutOfMemoryError
(三)有缆、虛擬機(jī)棧(Java Virtual Machine Stacks)
虛擬機(jī)棧是每個(gè)線程獨(dú)有的象踊,隨著線程的創(chuàng)建而存在,線程結(jié)束而死亡棚壁。它存儲(chǔ)的是局部變量表杯矩、操作數(shù)棧、動(dòng)態(tài)鏈接和方法的出口等信息袖外。但是在虛擬機(jī)棧內(nèi)存不夠的時(shí)候會(huì)OutOfMemoryError史隆,在線程運(yùn)行中需要更大的虛擬機(jī)棧時(shí)會(huì)出現(xiàn)StackOverFlowError.
(四)、本地方法棧(Native Method Stacks)
本地方法棧允許java程序調(diào)用底層封裝的C語(yǔ)言編寫(xiě)的方法實(shí)現(xiàn)曼验,如果在線程需要使用本地方法棧的時(shí)候泌射,JVM會(huì)為每個(gè)線程創(chuàng)建一個(gè)头镊。與虛擬機(jī)棧一樣在一些情況下會(huì)出現(xiàn)OutOfMemoryError或者StackOverFlowError
(五)、程序計(jì)數(shù)器(Program Counter Register)
由于JVM可以并發(fā)執(zhí)行線程魄幕,因此會(huì)存在線程之間的切換相艇,而這個(gè)時(shí)候就程序計(jì)數(shù)器會(huì)記錄下當(dāng)前程序執(zhí)行到的位置,以便在其他線程執(zhí)行完畢后纯陨,恢復(fù)現(xiàn)場(chǎng)繼續(xù)執(zhí)行坛芽。JVM會(huì)為每個(gè)線程分配一個(gè)程序計(jì)數(shù)器,與線程的生命周期相同翼抠。
(六) 運(yùn)行時(shí)常量池(Runtime Constant Pool )
運(yùn)行時(shí)常量池是類文件中常量池表的運(yùn)行時(shí)形式咙轩,它包含編譯時(shí)已知的常量信息、必須在運(yùn)行時(shí)解析的方法和字段引用等信息阴颖。
任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者Jackieonway獲得授權(quán)并注明出處活喊。
微信搜索"JackieOnWay"關(guān)注我們,第一時(shí)間獲取最新技術(shù)文摘量愧。