基礎(chǔ)積累:類加載過程引申JVM內(nèi)存結(jié)構(gòu)

前言

了解dubbo的時候火的,因?yàn)镾PI機(jī)制用到了動態(tài)代理的機(jī)制赠法,從而涉及到了類加載機(jī)制相關(guān)的東西麦轰,整個概念也屬于非常底層的邏輯,也好久沒整理了砖织,現(xiàn)整理一下款侵,便于后續(xù)翻閱。
盡可能的關(guān)聯(lián)JVM相關(guān)的知識點(diǎn)侧纯,如果讀者有補(bǔ)充的可以留言補(bǔ)充新锈。

類加載機(jī)制概念

Java虛擬機(jī)把描述類的數(shù)據(jù)從Class文件加載到內(nèi)存,并對數(shù)據(jù)進(jìn)行校驗(yàn)眶熬、轉(zhuǎn)換解析和初始化妹笆,最終形成可以被虛擬機(jī)直接使用的Java類型,這就是虛擬機(jī)的加載機(jī)制聋涨。*
Class文件由類裝載器裝載后晾浴,在JVM中將形成一份描述Class結(jié)構(gòu)的元信息對象,通過該元信息對象可以獲知Class的結(jié)構(gòu)信息:如構(gòu)造函數(shù)牍白,屬性和方法等脊凰,Java允許用戶借由這個Class相關(guān)的元信息對象間接調(diào)用Class對象的功能,這里就是我們經(jīng)常能見到的Class類。

類加載過程

image.png

類裝載器就是尋找類的字節(jié)碼文件茂腥,并構(gòu)造出類在JVM內(nèi)部表示的對象組件狸涌。主要要經(jīng)過以下步驟:

  • (1) 裝載:查找和導(dǎo)入Class文件;
  • (2) 鏈接:把類的二進(jìn)制數(shù)據(jù)合并到JRE中最岗;
    • (a)校驗(yàn):檢查載入Class文件數(shù)據(jù)的正確性帕胆;
    • (b)準(zhǔn)備:給類的靜態(tài)變量分配存儲空間;
    • (c)解析:將符號引用轉(zhuǎn)成直接引用般渡;
  • (3) 初始化:對類的靜態(tài)變量懒豹,靜態(tài)代碼塊執(zhí)行初始化操作

1.加載

類的裝載指的是將類的.class文件中的二進(jìn)制數(shù)據(jù)讀入到內(nèi)存中,將其放在運(yùn)行時數(shù)據(jù)區(qū)的方法區(qū)內(nèi)驯用,然后在堆區(qū)創(chuàng)建一個java.lang.Class對象脸秽,用來封裝類在方法區(qū)內(nèi)的數(shù)據(jù)結(jié)構(gòu)。
加載.class文件的方式有:

  • 1). 從本地系統(tǒng)中直接加載
  • 2). 通過網(wǎng)絡(luò)下載.class文件
  • 3). 從zip蝴乔,jar等歸檔文件中加載.class文件
  • 4). 從專有數(shù)據(jù)庫中提取.class文件
  • 5). 將Java源文件動態(tài)編譯為.class文件

2.驗(yàn)證

驗(yàn)證的目的是為了確保class文件中的字節(jié)流包含的信息流符合虛擬機(jī)的規(guī)范记餐,因此,不同的虛擬機(jī)可能有不同的實(shí)現(xiàn)薇正,大致可分為以下幾步:

  • 1)文件格式的驗(yàn)證:驗(yàn)證字節(jié)流是否符合Class文件格式的規(guī)范片酝,經(jīng)過該階段的驗(yàn)證后囚衔,字節(jié)流才會進(jìn)入內(nèi)存的方法區(qū)中進(jìn)行存儲,后面的三個驗(yàn)證都是基于方法區(qū)的存儲結(jié)構(gòu)進(jìn)行的雕沿。
  • 2)元數(shù)據(jù)驗(yàn)證:對類中的各數(shù)據(jù)類型進(jìn)行語法校驗(yàn)练湿,保證不存在不符合Java語法規(guī)范的元數(shù)據(jù)信息。
  • 3)字節(jié)碼驗(yàn)證:該階段驗(yàn)證的主要工作是進(jìn)行數(shù)據(jù)流和控制流分析晦炊,對類的方法體進(jìn)行校驗(yàn)分析鞠鲜,以保證被校驗(yàn)的類的方法在運(yùn)行時不會做出危害虛擬機(jī)安全的行為。
  • 4)符號引用驗(yàn)證:這是最后一個階段的驗(yàn)證断国,它發(fā)生在虛擬機(jī)將符號引用轉(zhuǎn)化為直接引用的時候贤姆,主要是對類自身以外的信息(常量池中的各種符號引用)進(jìn)行匹配性的校驗(yàn)。

3.準(zhǔn)備

準(zhǔn)備階段是正式為類變量分配內(nèi)存并設(shè)置類變量初始值的階段稳衬,這些內(nèi)存都將在方法區(qū)中進(jìn)行分配

  • 1)這時候進(jìn)行內(nèi)存分配的僅包括類變量(static)霞捡,而不包括實(shí)例變量,實(shí)例變量會在對象實(shí)例化時隨著對象一塊分配在Java堆中薄疚。
    2)這里所設(shè)置的初始值通常情況下是數(shù)據(jù)類型默認(rèn)的初始值值(如0碧信、0L、null街夭、false等)砰碴,具體的賦值是在初始化過程中,而常量是在這個時候進(jìn)行賦值的板丽。

解析

解析階段是虛擬機(jī)將常量池內(nèi)的符號引用替換為直接引用的過程呈枉。

  • 1)、類或接口的解析:判斷所要轉(zhuǎn)化成的直接引用是對數(shù)組類型埃碱,還是普通的對象類型的引用猖辫,從而進(jìn)行不同的解析。
  • 2)砚殿、字段解析:對字段進(jìn)行解析時啃憎,會先在本類中查找是否包含有簡單名稱和字段描述符都與目標(biāo)相匹配的字段,如果有似炎,則查找結(jié)束辛萍;如果沒有,則會按照繼承關(guān)系從上往下遞歸搜索該類所實(shí)現(xiàn)的各個接口和它們的父接口羡藐,還沒有叹阔,則按照繼承關(guān)系從上往下遞歸搜索其父類,直至查找結(jié)束传睹。
  • 3)、類方法解析:對類方法的解析與對字段解析的搜索步驟差不多岸晦,只是多了判斷該方法所處的是類還是接口的步驟欧啤,而且對類方法的匹配搜索睛藻,是先搜索父類,再搜索接口邢隧。
  • 4)店印、接口方法解析:與類方法解析步驟類似,只是接口不會有父類倒慧,因此按摘,只遞歸向上搜索父接口就行了。
初始化

類初始化階段是類加載過程的最后一步纫谅,為類的靜態(tài)變量賦予正確的初始值炫贤,JVM負(fù)責(zé)對類進(jìn)行初始化,主要對類變量進(jìn)行初始化付秕。在Java中對類變量進(jìn)行初始值設(shè)定有兩種方式:

  • ①聲明類變量時指定初始值
  • ②使用靜態(tài)代碼塊為類變量指定初始值

以上也可知兰珍,方法區(qū)存儲了靜態(tài)變量類信息
中存儲了類變量局部變量
擴(kuò)展:即時編譯器(JIT Just In Time)編譯后的一些熱點(diǎn)代碼也會存放在方法區(qū)
常量數(shù)據(jù)在編譯訪問常量的代碼時才會放入方法區(qū)中询吴。
由上面介紹可以知道掠河,方法區(qū)存放著各線程都可用的數(shù)據(jù),因此是線程共享的猛计。

類的實(shí)例化

類實(shí)例化的一般過程是:
父類的類構(gòu)造器<clinit>() -> 子類的類構(gòu)造器<clinit>() -> 父類的成員變量和實(shí)例代碼塊 -> 父類的構(gòu)造函數(shù) -> 子類的成員變量和實(shí)例代碼塊 -> 子類的構(gòu)造函數(shù)->靜態(tài)代碼塊->方法唠摹。
在類的實(shí)例化過程中,首先會在虛擬機(jī)棧中奉瘤,保存實(shí)例對象的引用勾拉,具體對象的屬性實(shí)例會存放在中。
擴(kuò)展:這里也可以理解垃圾的生成

Test testA = new Test();
Test testB = new Test();
testA.setName("a");
testB.setName("b");
testB = testA;

以上偽代碼可解釋毛好,當(dāng)引用關(guān)系變化時望艺,原有testB.setName("b");所對應(yīng)的堆中的內(nèi)存就可以當(dāng)做垃圾回收。
除了對象實(shí)例肌访,還包括數(shù)組找默,所以這也解釋為什么會報java.lang.OutOfMemoryError: Requested array size exceeds VM limit

方法調(diào)用

當(dāng)線程執(zhí)行一個方法時,就會隨之創(chuàng)建一個對應(yīng)的棧幀吼驶,并將建立的棧幀壓棧惩激。
局部變量表(Local Variables)操作數(shù)棧(Operand Stack)蟹演、指向當(dāng)前方法所屬的類的運(yùn)行時常量池(運(yùn)行時常量池的概念在方法區(qū)部分會談到)的引用(Reference to runtime constant pool)风钻、方法返回地址(Return Address)和一些額外的附加信息壓入虛擬機(jī)棧中。
這也就解釋了為什么遞歸過多會導(dǎo)致StackOverflowError酒请,因?yàn)闀粩嗟耐鶙V袎喝?code>方法返回地址骡技。
這部分是在線程執(zhí)行方法時生成,故也可以知是線程私有的。
擴(kuò)展:程序計數(shù)器存儲當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器布朦。指向下一條要執(zhí)行的指令囤萤。因此也是線程私有的。

JVM內(nèi)存結(jié)構(gòu)

image.png

堆的作用是存放對象實(shí)例數(shù)組是趴。從結(jié)構(gòu)上來分涛舍,可以分為新生代老年代。而新生代又可以分為Eden 空間唆途、From Survivor 空間(s0)富雅、To Survivor 空間(s1)。 所有新生成的對象首先都是放在新生代的肛搬。需要注意没佑,Survivor的兩個區(qū)是對稱的,沒先后關(guān)系滚婉,所以同一個區(qū)中可能同時存在從Eden復(fù)制過來的對象图筹,和從前一個Survivor復(fù)制過來的對象,而復(fù)制到老年代的只有從第一個Survivor區(qū)過來的對象让腹。而且远剩,Survivor區(qū)總有一個是空的。
如圖:-Xms設(shè)置堆的最小空間大小骇窍。-Xmx設(shè)置堆的最大空間大小瓜晤。-XX:NewSize設(shè)置新生代最小空間大小。-XX:MaxNewSize設(shè)置新生代最小空間大小腹纳。

方法區(qū)

方法區(qū)(Method Area)與Java 堆一樣痢掠,是各個線程共享的內(nèi)存區(qū)域,也有人把方法區(qū)稱為“永久代”(Permanent Generation)嘲恍,在Java8中永生代徹底消失了足画。
如圖:-XX:PermSize 設(shè)置最小空間 -XX:MaxPermSize 設(shè)置最大空間。

方法棧

每個線程會有一個私有的棧佃牛。每個線程中方法的調(diào)用又會在本棧中創(chuàng)建一個棧幀淹辞。
如圖:-Xss控制每個線程棧的大小。

本地方法棧

本地方法棧(Native Method Stacks)與虛擬機(jī)棧所發(fā)揮的作用是非常相似的俘侠,其區(qū)別不過是虛擬機(jī)棧為虛擬機(jī)執(zhí)行Java 方法(也就是字節(jié)碼)服務(wù)象缀,而本地方法棧則是為虛擬機(jī)使用到的Native 方法服務(wù)。
如圖:-Xss控制每個線程的大小爷速。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末央星,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惫东,更是在濱河造成了極大的恐慌莉给,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異禁谦,居然都是意外死亡胁黑,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門州泊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人漂洋,你說我怎么就攤上這事遥皂。” “怎么了刽漂?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵演训,是天一觀的道長。 經(jīng)常有香客問我贝咙,道長样悟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任庭猩,我火速辦了婚禮窟她,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蔼水。我一直安慰自己震糖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布趴腋。 她就那樣靜靜地躺著吊说,像睡著了一般。 火紅的嫁衣襯著肌膚如雪优炬。 梳的紋絲不亂的頭發(fā)上颁井,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機(jī)與錄音蠢护,去河邊找鬼雅宾。 笑死,一個胖子當(dāng)著我的面吹牛糊余,可吹牛的內(nèi)容都是我干的秀又。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼贬芥,長吁一口氣:“原來是場噩夢啊……” “哼吐辙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蘸劈,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤昏苏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贤惯,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洼专,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了孵构。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屁商。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颈墅,靈堂內(nèi)的尸體忽然破棺而出蜡镶,到底是詐尸還是另有隱情,我是刑警寧澤恤筛,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布官还,位于F島的核電站,受9級特大地震影響毒坛,放射性物質(zhì)發(fā)生泄漏望伦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一煎殷、第九天 我趴在偏房一處隱蔽的房頂上張望屯伞。 院中可真熱鬧,春花似錦蝌数、人聲如沸愕掏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽饵撑。三九已至,卻和暖如春唆貌,著一層夾襖步出監(jiān)牢的瞬間滑潘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工锨咙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留语卤,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓酪刀,卻偏偏與公主長得像粹舵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子骂倘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348