Java虛擬機總結(jié)給面試的你(中)

本篇博客主要針對Java虛擬機的類加載機制郭赐,虛擬機字節(jié)碼執(zhí)行引擎,早期編譯優(yōu)化進行總結(jié),其余部分總結(jié)請點擊Java虛擬總結(jié)上篇 萧落。

一.虛擬機類加載機制

概述

虛擬機把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存嚎幸,并對數(shù)據(jù)進行校驗颜矿、轉(zhuǎn)換解析和初始化,最終形成可以被虛擬機直接使用的Java類型嫉晶,這就是虛擬機的類加載機制骑疆。

類加載的時機

類加載的時機不止一種:

  • 遇到new等字節(jié)碼指令時會進行類加載
  • 反射調(diào)用時會進行類加載

在初始化時,若待初始化的類有父類則其父類先進行初始化(接口除外),并且先初始化包含main的主類替废。需要注意的是子類引用父類非final靜態(tài)變量時箍铭,只初始化靜態(tài)變量所在類,即父類椎镣,而引用final類型static變量不會引起任何初始化诈火,因為其編譯期間就已經(jīng)儲存在常量池中了。另外數(shù)組定義也是不會引發(fā)類的初始化状答。比如

Student[] stus=new Student[10];

是不會引起Student類的初始化的冷守。

類加載的過程

加載過程

通過類的全限定名來獲取定義此類的二進制字節(jié)流,將這個字節(jié)流所代表的靜態(tài)存儲結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運行時數(shù)據(jù)結(jié)構(gòu)惊科,在內(nèi)存中生成一個代表類的數(shù)據(jù)訪問入口的java.lang.Class對象拍摇。

驗證過程

驗證過程的目的是為了確保Class文件的字節(jié)流中包含的信息符合當前虛擬機的要求,并且不會危害虛擬機自身的安全馆截。主要有

  • 文件格式驗證:驗證魔數(shù)充活,主次版本號,常量類型等蜡娶。
  • 元數(shù)據(jù)驗證:是否有父類混卵,是否繼承了不該繼承的類,抽象類是否實現(xiàn)了方法等窖张。
  • 字節(jié)碼驗證:確保程序語義是合法的幕随,符合邏輯的。如類型轉(zhuǎn)換荤堪,跳轉(zhuǎn)指令等合陵。
  • 符號引用驗證:對類自身以外的信息(常量池中的各種引用)進行匹配校驗。

準備過程

正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段,只包括類變量而不包括實例變量和final類變量澄阳,而且僅僅只是初始化為0值拥知。

解析過程

虛擬機將常量池內(nèi)的符號引用轉(zhuǎn)換為直接引用的過程。符號引用用一組符號來描述所引用的目標碎赢。而直接引用是直接指向目標的指針低剔,相對偏移量或是一個能間接定位到目標的句柄。

初始化階段

在初始化階段真正開始執(zhí)行Java程序代碼(字節(jié)碼),執(zhí)行類的構(gòu)造器<clinit>()方法,<clinit>()方法是由編譯器自動收集所有類變量的賦值動作和靜態(tài)語句塊的語句合并而成,同一類中的靜態(tài)塊與類變量按順序初始化,在同一個加載器下襟齿,一個類只會被初始化一次姻锁。

類加載器

實現(xiàn)通過一個類的全限定名獲取描述此類的二進制字節(jié)流的代碼模塊稱為類加載器。比較兩個類是否相等猜欺,一定是在同一個類加載器的前提下進行的位隶,否則哪怕Class文件都一樣也不相等

類加載器的分類

  • 啟動類加載器, 負責將存放在<JAVA_HOME>\lib目錄或-Xbootclasspath參數(shù)指定的路徑中的類庫加載到內(nèi)存中开皿。
  • 擴展類加載器涧黄,負責加載<JAVA_HOME>\lib\ext目錄或java.ext.dirs系統(tǒng)變量指定的路徑中的所有類庫。
  • 應(yīng)用程序類加載器赋荆,負責加載用戶類路徑(classpath)上的指定類庫笋妥,我們可以直接使用這個類加載器。一般情況窄潭,如果我們沒有自定義類加載器默認就是用這個加載器春宣。

雙親委派模型

雙親委派模型

雙親委派模型工作過程是:如果一個類加載器收到類加載的請求,它首先不會自己去嘗試加載這個類嫉你,而是把這個請求委派給父類加載器完成月帝。每個類加載器都是如此,只有當父加載器在自己的搜索范圍內(nèi)找不到指定的類時(即ClassNotFoundException)均抽,子加載器才會嘗試自己去加載嫁赏。

這樣做的好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層次關(guān)系。

二.虛擬機字節(jié)碼執(zhí)行引擎

虛擬機的執(zhí)行引擎自行實現(xiàn)油挥,可以自行制定指令集與執(zhí)行引擎的結(jié)構(gòu)體系。

棧幀

棧幀是用于支持虛擬機進行方法調(diào)用和方法執(zhí)行的數(shù)據(jù)結(jié)構(gòu)款熬,是虛擬機棧的棧元素深寥。它儲存了方法的局部變量表,操作數(shù)棧贤牛,動態(tài)鏈接惋鹅,方法返回地址,對于活動線程來說殉簸,只有棧頂?shù)臈攀怯行У娜蚣Q為當前棧幀,與其關(guān)聯(lián)的方法叫做當前方法般卑。

局部變量表

局部變量表存放方法參數(shù)和方法內(nèi)部定義的變量武鲁。單位是slot(槽),最大可以達到32位蝠检。垃圾回收時沐鼠,slot可以復(fù)用,將不使用的變量置為null是有意義的,方便垃圾回收饲梭。局部變量不像類變量乘盖,是沒有初始值的。

JIT編譯器

當虛擬機發(fā)現(xiàn)某個方法或代碼塊運行特別頻繁時憔涉,就會把這些代碼認定為 “Hot Spot Code”(熱點代碼)订框,為了提高熱點代碼的執(zhí)行效率,在運行時兜叨,虛擬機將會把這些代碼編譯成與本地平臺相關(guān)的機器碼穿扳,并進行各層次的優(yōu)化,完成這項任務(wù)的正是 JIT 編譯器浪腐。

方法返回地址

  • 遇到方法的返回指令-->正常完成出口
  • 遇到異常并且未處理-->異常完成出口纵揍,不會給上層調(diào)用者產(chǎn)生任何返回值

方法調(diào)用

方法在編譯時并不確定方法的真實地址,而是一個符號引用议街,使得Java的動態(tài)擴展能力提升泽谨,在類加載過程甚至運行時才確定目標方法的直接引用。

解析

在類的解析階段將一部分符號引用轉(zhuǎn)換為直接引用特漩,這部分符號引用代表的方法必須“編譯期可知吧雹,運行時不變”,如靜態(tài)方法涂身,私有方法雄卷,實例構(gòu)造器,父類方法蛤售。final方法也是丁鹉。

分派

靜態(tài)分派(與重載相關(guān)),依賴靜態(tài)類型來定位方法執(zhí)行版本的分派動作悴能。自動轉(zhuǎn)型順序:char->int->long->float->double->Character->Serializable->Object->char...

動態(tài)分派(重寫相關(guān))揣钦,找到操作數(shù)棧頂?shù)牡谝粋€元素所指向的對象的實際類型,若常量池中的描述符和簡單名稱都相符漠酿,則返回直接引用冯凹,否則對其父類進行第二步。

動態(tài)分配的實現(xiàn):

動態(tài)分配的實現(xiàn)

在類的方法區(qū)建立一個虛方法表提升效率炒嘲,若子類未重寫父類的方法宇姚,則子類的繼承方法中地址和父類方法的地址是一樣的,若重寫了父類的方法夫凸,則子類的方法地址就會改變浑劳,指向自己實現(xiàn)的版本。如上圖Son的clone方法沒有被重寫寸痢,指向的是Object父類的地址呀洲,而hardChoice方法被重寫了,指向的是Son自己實現(xiàn)的地址。

動態(tài)類型語言

類型檢查的主題過程在運行期而不是在編譯期道逗,如Python兵罢,Javascript,Ruby滓窍,PHP卖词,與之相對的就是靜態(tài)語言。

解釋執(zhí)行與編譯執(zhí)行

解釋執(zhí)行為邊解釋邊執(zhí)行吏夯,編譯執(zhí)行則是先將源代碼編譯成目標語言 (如: 機器語言) 之后通過連接程序連接到生成的目標程序進行執(zhí)行此蜈。

基于棧的字節(jié)碼解釋執(zhí)行引擎

  • 基于棧的指令集:Java編譯器輸出的指令流
  • 基于寄存器的指令集:x86匯編

三.早期編譯器優(yōu)化

編譯器

三種編譯器:

  • 前端編譯器:把.java變成.class的過程,eg:Javac
  • 后端運行期編譯器(JIT):把字節(jié)碼變成機器碼的過程,eg:Hotpot的C1噪生,C2編譯器
  • 靜態(tài)提前編譯器(AOT):直接把*.java變成機器碼的過程裆赵,eg:GCJ(GNU Compiler for the Java)

解析與填充符號表

詞法分析

標記是編譯過程的最小元素,關(guān)鍵字跺嗽、變量名战授、字面量、運算符都可以成為標記桨嫁,詞法分析就是將源代碼的字符流轉(zhuǎn)變?yōu)闃擞浖稀?/p>

語法分析

語法分析是根據(jù)Token序列構(gòu)造抽象語法樹的過程植兰。抽象語法樹是用來描述程序代碼語法結(jié)構(gòu)的樹形表示方法,每一個節(jié)點都代表著程序代碼的一個語法結(jié)構(gòu):包璃吧,類型楣导,修飾符等。

注解處理器

類似編譯器的一種插件畜挨,如果插件對語法樹進行了修改筒繁,編譯器將回到解析及填充符號表的過程重新處理。

語義分析

對語法抽象樹進行上下文有關(guān)性質(zhì)的審查巴元,如類型檢查膝晾。

字節(jié)碼生成

將前面各個步驟生成的信息轉(zhuǎn)換成字節(jié)碼寫到磁盤中,類構(gòu)造器<cinit>和實例構(gòu)造器<init>就是在這個階段添加到語法樹中务冕。

Java語法糖

  • 泛型與類型擦除:與C#不一樣,Java的泛型是偽泛型幻赚,在生成的字節(jié)碼中已經(jīng)被替換成了原生類型了禀忆,會自動加上類型轉(zhuǎn)換。
  • 遍歷:自動轉(zhuǎn)換為iterator遍歷落恼。
  • 裝箱與拆箱:==運算在不遇到算數(shù)運算的情況下不會自動拆箱箩退。equals方法不會處理數(shù)據(jù)的類型轉(zhuǎn)換,而==會佳谦。

條件編譯

編譯器不會編譯if到達不到的語句戴涝,也就是取消分支不成立的代碼塊,可以查看反編譯后的代碼驗證條件編譯。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末啥刻,一起剝皮案震驚了整個濱河市奸鸯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌可帽,老刑警劉巖娄涩,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異映跟,居然都是意外死亡蓄拣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門努隙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來球恤,“玉大人,你說我怎么就攤上這事荸镊⊙矢” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵贷洲,是天一觀的道長收厨。 經(jīng)常有香客問我,道長优构,這世上最難降的妖魔是什么诵叁? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮钦椭,結(jié)果婚禮上拧额,老公的妹妹穿的比我還像新娘。我一直安慰自己彪腔,他們只是感情好侥锦,可當我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著德挣,像睡著了一般恭垦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上格嗅,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天番挺,我揣著相機與錄音,去河邊找鬼屯掖。 笑死玄柏,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的贴铜。 我是一名探鬼主播粪摘,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼瀑晒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了徘意?” 一聲冷哼從身側(cè)響起苔悦,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎映砖,沒想到半個月后间坐,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡邑退,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年竹宋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片地技。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜈七,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出莫矗,到底是詐尸還是另有隱情飒硅,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布作谚,位于F島的核電站三娩,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妹懒。R本人自食惡果不足惜雀监,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望眨唬。 院中可真熱鬧会前,春花似錦、人聲如沸匾竿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽岭妖。三九已至临庇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昵慌,已是汗流浹背苔巨。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留废离,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓礁芦,卻偏偏與公主長得像蜻韭,于是被迫代替她去往敵國和親悼尾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 《深入理解Java虛擬機》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分肖方。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,087評論 1 34
  • 一闺魏、運行時數(shù)據(jù)區(qū)域 Java虛擬機管理的內(nèi)存包括幾個運行時數(shù)據(jù)內(nèi)存:方法區(qū)、虛擬機棧俯画、本地方法棧析桥、堆、程序計數(shù)器,...
    加油小杜閱讀 1,518評論 1 15
  • 注:此文是我在讀完周志明老師的深入理解Java虛擬機之后總結(jié)的一篇文章,請閱讀此書獲取更加詳細的信息. 類加載的時...
    AlstonWilliams閱讀 492評論 0 0
  • 如果可以的話瓮顽,我真想變成爸爸的手機岸滋谩!這樣的話爆阶,他就會一天到晚的把我捧在手心。 打電話的時候,他會觸摸我的耳朵截亦,鼻...
    素衣煙霞閱讀 322評論 0 3
  • 秋風漸起,落葉堆積成的傷痕柬讨,被蒼白的回憶撕扯崩瓤! 倚在窗前,聽歲月輪回所講下的故事踩官!在古韻悠然的琴聲里漸遠却桶! 寒山寺...
    燈滅人走遠閱讀 114評論 0 0