JVM 類加載

類文件的結(jié)構(gòu)

一比勉、魔數(shù)(Magic Number)

每個(gè) Class 文件的頭 4 個(gè)字節(jié)稱為魔數(shù)(Magic Number),它的唯一作用是確定這個(gè)文件是否為一個(gè)能被虛擬機(jī)接收的 Class 文件劳较。

二、Class 文件版本號(hào)(Minor&Major Version)

緊接著魔數(shù)的四個(gè)字節(jié)存儲(chǔ)的是 Class 文件的版本號(hào):前兩個(gè)字節(jié)是次版本號(hào)浩聋,后兩個(gè)字節(jié)是主版本號(hào)观蜗。

每當(dāng) Java 發(fā)布大版本(比如 Java 7,Java8)的時(shí)候衣洁,主版本號(hào)都會(huì)加 1墓捻。

高版本的 Java 虛擬機(jī)可以執(zhí)行低版本編譯器生成的 Class 文件,但是低版本的 Java 虛擬機(jī)不能執(zhí)行高版本編譯器生成的 Class 文件坊夫。

三砖第、常量池(Constant Pool)

緊接著主次版本號(hào)之后的是常量池,常量池的數(shù)量是兩個(gè)字節(jié)的 constant_pool_count-1(常量池計(jì)數(shù)器是從 1 開始計(jì)數(shù)的环凿,第 0 項(xiàng)常量有特殊考慮梧兼,當(dāng)值為 0 代表“不引用任何一個(gè)常量池項(xiàng)”)。

常量池主要存放:字面量符號(hào)引用智听,字面量是比如字符串羽杰、final常量。

符號(hào)引用包含三類:

  • 類和接口的全限定名到推。
  • 字段的名稱和描述。
  • 方法的名稱和描述莉测。

常量池中的每一項(xiàng)都是一個(gè)表捣卤,這個(gè)表的第一位都是用來(lái)標(biāo)識(shí)常量類型的腌零。

四、訪問(wèn)標(biāo)識(shí)(Access Flags)

標(biāo)識(shí)類或接口的層次的訪問(wèn)信息,包括這個(gè)Class是類還是接口闲询,是否為public或者abstract類型,如果是類的話阎姥,是否被申明為final等呼巴。

五御蒲、當(dāng)前類(This Class)厚满、父類(Super Class)、接口(Interfaces)索引集合

u2             this_class;//當(dāng)前類全限定名
u2             super_class;//父類全限定名
u2             interfaces_count;//實(shí)現(xiàn)的接口數(shù)量
u2             interfaces[interfaces_count];//一個(gè)類可以實(shí)現(xiàn)多個(gè)接口

六遵馆、字段表集合(Fields)

字段數(shù)量:兩個(gè)字節(jié)描述字段數(shù)量货邓。

字段表:字段表中的項(xiàng)包括訪問(wèn)標(biāo)識(shí)换况、名稱、對(duì)常量池的引用复隆、一些額外的屬性挽拂。

字段表用于描述接口或類中聲明的變量亏栈。字段包括類級(jí)變量以及實(shí)例變量宏赘,但不包括在方法內(nèi)部聲明的局部變量察署。

七、方法集合(Methods)

方法數(shù)量:兩個(gè)字節(jié)標(biāo)識(shí)方法數(shù)量

方法表:方法表與字段表類似休吠,表中項(xiàng)包括訪問(wèn)標(biāo)識(shí)业簿、名稱梅尤、對(duì)常量池的引用巷燥、一些額外的屬性。

八亡脑、屬性表(Attributes)

與字段和方法類似霉咨,Class文件也有自己的屬性表集合途戒。

類加載

類的生命周期僵驰?

  • 加載 -> 連接 -> 初始化 -> 使用 -> 卸載

  • 連接又分為三步:驗(yàn)證 -> 準(zhǔn)備 -> 解析

一蒜茴、類加載

類加載主要完成三件事:

  • 通過(guò)全類名獲取定義此類的二進(jìn)制字節(jié)流
  • 將字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)換為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
  • 在內(nèi)存中生成一個(gè)代表該類的 Class 對(duì)象粉私,作為方法區(qū)這些數(shù)據(jù)的訪問(wèn)入口

二诺核、驗(yàn)證

  • 文件格式驗(yàn)證:如魔數(shù)是否正確,主版本號(hào)是否能被當(dāng)前虛擬機(jī)處理漓摩,常量池的類型是否被支持管毙。
  • 元數(shù)據(jù)驗(yàn)證:對(duì)字節(jié)碼描述的信息進(jìn)行語(yǔ)義分析,例如:類是否有父類酥诽,是否繼承了不該被繼承的類等
  • 字節(jié)碼驗(yàn)證:通過(guò)數(shù)據(jù)流和控制流分析皱埠,確定程序語(yǔ)義是否合法边器、符合邏輯托修。比如保證任意時(shí)刻操作數(shù)棧和指令代碼序列都能配合工作睦刃。
  • 符號(hào)引用驗(yàn)證:確保解析動(dòng)作能正確執(zhí)行。

三际长、準(zhǔn)備

準(zhǔn)備階段正式為類變量分配內(nèi)存并設(shè)置類變量初始值工育。注意點(diǎn):

  • 這時(shí)候進(jìn)行內(nèi)存分配的僅包括類變量如绸,即靜態(tài)變量怔接,而不包括實(shí)例變量扼脐。實(shí)例變量會(huì)在對(duì)象實(shí)例化時(shí)隨著對(duì)象一塊分配在 Java 堆中靶端。
  • 從概念上講脏榆,類變量所使用的內(nèi)存都應(yīng)當(dāng)在 方法區(qū) 中進(jìn)行分配台谍。JDK 7 之后,HotSpot 已經(jīng)把原本放在永久代的字符串常量池仔役、靜態(tài)變量等移動(dòng)到堆中又兵,這個(gè)時(shí)候類變量則會(huì)隨著 Class 對(duì)象一起存放在 Java 堆中沛厨。
  • 里所設(shè)置的初始值"通常情況"下是數(shù)據(jù)類型默認(rèn)的零值(如 0逆皮、0L电谣、null剿牺、false 等)况鸣,只有final才在準(zhǔn)備階段賦值。

四潜索、解析

解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程竹习。解析動(dòng)作主要針對(duì)類或接口整陌、字段、類方法九默、接口方法驼修、方法類型、方法句柄和調(diào)用限定符 7 類符號(hào)引用進(jìn)行幢竹。

五焕毫、初始化

初始化階段是執(zhí)行初始化方法方法的過(guò)程咬荷,是類加載的最后一步,同時(shí)也是對(duì)象創(chuàng)建的第一步唇牧,這一步 JVM 才開始真正執(zhí)行類中定義的 Java 程序代碼(字節(jié)碼)聚唐。

對(duì)于初始化方法的調(diào)用丐重,虛擬機(jī)會(huì)自己確保其在多線程環(huán)境中的安全性。因?yàn)榉椒ㄊ菐фi線程安全杆查,所以在多線程環(huán)境下進(jìn)行類初始化的話可能會(huì)引起多個(gè)進(jìn)程阻塞扮惦,并且這種阻塞很難被發(fā)現(xiàn)。

虛擬機(jī)對(duì)類進(jìn)行初始化的五種情況亲桦?
  • 當(dāng)遇到 new 新對(duì)象崖蜜,訪問(wèn)靜態(tài)變量(不是靜態(tài)常量,靜態(tài)常量在常量池中)客峭,給靜態(tài)變量賦值豫领、調(diào)用類的靜態(tài)方法,會(huì)初始化類舔琅。
  • 使用 java 反射對(duì)類進(jìn)行反射調(diào)用等恐,比如 newInstance(), Class.forname("...")等郊尝,如果類沒有初始化样傍,會(huì)觸發(fā)類初始化襟锐。
  • 初始化一個(gè)類,如果其父類還未初始化,則先觸發(fā)該父類的初始化。
  • 當(dāng)虛擬機(jī)啟動(dòng)時(shí),用戶需要定義一個(gè)要執(zhí)行的主類 (包含 main 方法的那個(gè)類),虛擬機(jī)會(huì)先初始化這個(gè)類。
  • MethodHandleVarHandle 可以看作是輕量級(jí)的反射調(diào)用機(jī)制,而要想使用這 2 個(gè)調(diào)用, 就必須先使用 findStaticVarHandle 來(lái)初始化要調(diào)用的類。
  • 當(dāng)一個(gè)接口中定義了 JDK8 新加入的默認(rèn)方法時(shí),如果有這個(gè)接口的實(shí)現(xiàn)類發(fā)生了初始化,那該接口要在其之前被初始化高镐。

六算行、卸載

  1. 該類的所有的實(shí)例對(duì)象都已被 GC鲸阔,也就是說(shuō)堆不存在該類的實(shí)例對(duì)象叙身。
  2. 該類沒有在其他任何地方被引用(不被反射調(diào)用财忽,class.forname(""))
  3. 該類的類加載器的實(shí)例已被 GC

所以隶校,在 JVM 生命周期內(nèi)舞终,由 jvm 自帶的類加載器加載的類是不會(huì)被卸載的。但是由我們自定義的類加載器加載的類是可能被卸載的转捕。

類加載器總結(jié)枢步?

JVM內(nèi)置了三個(gè)重要的類加載器殴穴。

  • BootstrapClassLoader(啟動(dòng)類加載器):最頂層類加載器,由 C++實(shí)現(xiàn)淤堵。負(fù)責(zé)加載 %JAVA_HOME%/lib目錄下的 jar 包和類扎阶,或者被 -Xbootclasspath參數(shù)指定的路徑中的所有類。
  • ExtensionClassLoader(擴(kuò)展類加載器) :主要負(fù)責(zé)加載 %JRE_HOME%/lib/ext 目錄下的 jar 包和類孟害,或被 java.ext.dirs 系統(tǒng)變量所指定的路徑下的 jar 包。
  • AppClassLoader(應(yīng)用程序類加載器) :面向我們用戶的加載器惯雳,負(fù)責(zé)加載當(dāng)前應(yīng)用 classpath 下的所有 jar 包和類捍歪。

類加載的雙親委派模式恩商?

  • 自底向上檢查類是否被加載损拢,如果加載過(guò)或舞,直接返回。
  • 自頂向下嘗試加載類丑蛤,如果頂層類加載器加載失敗叠聋,才會(huì)由底層類加載器加載。
  • 首先檢查用戶自定義類是否加載了此類受裹,然后檢查應(yīng)用程序類加載器碌补,擴(kuò)展類加載器,啟動(dòng)類加載器棉饶。最后依次由上到下嘗試加載厦章。

雙親委派模式的好處?

  • 雙親委派模型可以避免類的重復(fù)加載(JVM 區(qū)分不同類的方式不僅僅根據(jù)類名照藻,相同的類文件被不同的類加載器加載產(chǎn)生的是兩個(gè)不同的類)袜啃。

  • 也保證了 Java 的核心 API 不被篡改。如果沒有使用雙親委派模型幸缕,而是每個(gè)類加載器加載自己的話就會(huì)出現(xiàn)一些問(wèn)題群发,比如我們編寫一個(gè)稱為 java.lang.Object 類的話,那么程序運(yùn)行的時(shí)候发乔,系統(tǒng)就會(huì)出現(xiàn)多個(gè)不同的 Object 類熟妓。

如果我們不想用雙親委派模型怎么辦?

繼承ClassLoader類栏尚,重寫 loadClass() 方法起愈。

如何自定義類加載器?

除了 BootstrapClassLoader 其他類加載器均由 Java 實(shí)現(xiàn)且全部繼承自 java.lang.ClassLoader。如果我們要自定義自己的類加載器告材,很明顯需要繼承 ClassLoader坤次,并重寫 findClass() 方法。

jvm常見參數(shù)總結(jié)斥赋?

// 堆內(nèi)存 -Xms<heap size>[unit] 
-Xms2G                              堆初始化內(nèi)存2G
-Xmx5G                              最大內(nèi)存5G

// 新生代內(nèi)存  -XX:NewSize=<young size>[unit] 
-XX:NewSize=256m        新生代最小內(nèi)存256m
-XX:MaxNewSize=1024m  新生代最大內(nèi)存1024m

// 通過(guò)-Xmn<young size>[unit]指定新生代內(nèi)存
-Xmn256m                        新生代最大內(nèi)存和最小內(nèi)存都是256m
  
// 通過(guò) XX:NewRatio=<int> 設(shè)置新生代與老年代的比值
-XX:NewRatio=1              新生代:老年代 的比值為1:1

// 顯示的指定元空間的大小
-XX:MetaspaceSize=N //設(shè)置 Metaspace 的初始(和最小大戌趾铩)
-XX:MaxMetaspaceSize=N //設(shè)置 Metaspace 的最大大小,如果不指定大小的話疤剑,隨著更多類的創(chuàng)建滑绒,虛擬機(jī)會(huì)耗盡所有可用的系統(tǒng)內(nèi)存

 //顯示指定選擇垃圾收集器
 -XX:+UseSerialGC
 -XX:+UseParallelGC
 -XX:+UseParNewGC
 -XX:+UseG1GC
  

JVM 調(diào)優(yōu)

JVM 調(diào)優(yōu)常見工具?

JDK命令行工具:
  • jps:
  • jstat:
  • jmap:
  • jhat:
  • jhat:
JDK 可視化分析工具:
  • JConsole:

  • Visual VM:

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隘膘,一起剝皮案震驚了整個(gè)濱河市疑故,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌弯菊,老刑警劉巖纵势,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異管钳,居然都是意外死亡钦铁,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門才漆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牛曹,“玉大人,你說(shuō)我怎么就攤上這事醇滥±璞龋” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵鸳玩,是天一觀的道長(zhǎng)阅虫。 經(jīng)常有香客問(wèn)我,道長(zhǎng)不跟,這世上最難降的妖魔是什么书妻? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮躬拢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘见间。我一直安慰自己聊闯,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布米诉。 她就那樣靜靜地躺著菱蔬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拴泌,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天魏身,我揣著相機(jī)與錄音,去河邊找鬼蚪腐。 笑死箭昵,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的回季。 我是一名探鬼主播家制,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泡一!你這毒婦竟也來(lái)了颤殴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤鼻忠,失蹤者是張志新(化名)和其女友劉穎涵但,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帖蔓,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡矮瘟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了讨阻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芥永。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钝吮,靈堂內(nèi)的尸體忽然破棺而出埋涧,到底是詐尸還是另有隱情,我是刑警寧澤奇瘦,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布棘催,位于F島的核電站,受9級(jí)特大地震影響耳标,放射性物質(zhì)發(fā)生泄漏醇坝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一次坡、第九天 我趴在偏房一處隱蔽的房頂上張望呼猪。 院中可真熱鬧,春花似錦砸琅、人聲如沸宋距。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)谚赎。三九已至淫僻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間壶唤,已是汗流浹背雳灵。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留闸盔,地道東北人悯辙。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蕾殴,于是被迫代替她去往敵國(guó)和親笑撞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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