Java虛擬機(jī)內(nèi)存管理——內(nèi)存空間劃分

一、類加載過(guò)程仅颇,雙親委派模型

1.Java中類加載分為3個(gè)步驟:加載单默、鏈接、初始化忘瓦。
  • 加載搁廓。加載是將字節(jié)碼數(shù)據(jù)從不同的數(shù)據(jù)源讀取到JVM內(nèi)存,并映射為JVM認(rèn)可的數(shù)據(jù)結(jié)構(gòu),也就是Class對(duì)象的過(guò)程境蜕。數(shù)據(jù)源可以是Jar文件蝙场、Class文件等等。如果數(shù)據(jù)的格式并不是ClassFile的結(jié)構(gòu)粱年,則會(huì)報(bào)ClassFormatError售滤。
  • 鏈接。鏈接是類加載的核心部分逼泣,這一步分為3個(gè)步驟:驗(yàn)證趴泌、準(zhǔn)備、解析拉庶。

a. 驗(yàn)證嗜憔。驗(yàn)證是保證JVM安全的重要步驟。JVM需要校驗(yàn)字節(jié)信息是否符合規(guī)范氏仗,避免惡意信息和不規(guī)范數(shù)據(jù)危害JVM運(yùn)行安全吉捶。如果驗(yàn)證出錯(cuò),則會(huì)報(bào)VerifyError皆尔。
b.準(zhǔn)備呐舔。這一步會(huì)創(chuàng)建靜態(tài)變量,并為靜態(tài)變量開(kāi)辟內(nèi)存空間慷蠕。
c.解析珊拼。這一步會(huì)將符號(hào)引用替換為直接引用。

  • 初始化流炕。初始化會(huì)為靜態(tài)變量賦值澎现,并執(zhí)行靜態(tài)代碼塊中的邏輯。
2.雙親委派模型每辟。

類加載器大致分為3類:?jiǎn)?dòng)類加載器剑辫、擴(kuò)展類加載器、應(yīng)用程序類加載器渠欺。
啟動(dòng)類加載器主要加載 jre/lib下的jar文件妹蔽。
擴(kuò)展類加載器主要加載 jre/lib/ext 下的jar文件。
應(yīng)用程序類加載器主要加載 classpath下的文件挠将。

所謂的雙親委派模型就是當(dāng)加載一個(gè)類時(shí)胳岂,會(huì)優(yōu)先使用父類加載器加載,當(dāng)父類加載器無(wú)法加載時(shí)才會(huì)使用子類加載器去加載舔稀。這么做的目的是為了避免類的重復(fù)加載旦万。

3.Java程序執(zhí)行過(guò)程

.java ——編譯——> .class
類加載器負(fù)責(zé)加載各個(gè)字節(jié)碼文件(.class)
加載完.class后,由執(zhí)行引擎執(zhí)行镶蹋,在執(zhí)行過(guò)程中,需要運(yùn)行時(shí)數(shù)據(jù)區(qū)提供數(shù)據(jù)


image.png

二.內(nèi)存空間劃分

JMVS規(guī)定了,Java虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)的劃分贺归,應(yīng)當(dāng)分為如下幾塊:

程序計(jì)數(shù)器淆两、Java堆、Java虛擬機(jī)棧拂酣、本地方法棧秋冰、方法區(qū)

jvm.png

程序計(jì)數(shù)器(PC寄存器):線程私有。生命周期與線程相同婶熬,每創(chuàng)建一個(gè)線程就會(huì)創(chuàng)建出一個(gè)程序計(jì)數(shù)器剑勾。線程銷毀,計(jì)數(shù)器就銷毀赵颅。
每個(gè)線程有有一個(gè)私有的程序計(jì)數(shù)器虽另,任何時(shí)間一個(gè)線程都只會(huì)有一個(gè)方法正在執(zhí)行,也就是所謂的當(dāng)前方法饺谬。程序計(jì)數(shù)器存放的就是這個(gè)當(dāng)前方法的JVM指令地址捂刺。

  • 一塊較小的的內(nèi)存空間,它的作用可以看作是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器募寨。
  • 如果線程正在執(zhí)行的是一個(gè) Java 方法族展,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果正在執(zhí)行的是 Native 方法拔鹰,這個(gè)計(jì)數(shù)器值則為空仪缸。
  • 此內(nèi)存區(qū)域是唯一一個(gè)在 Java 虛擬機(jī)規(guī)范中沒(méi)有規(guī)定任何 OutOfMemoryError情況的區(qū)域。
    通俗的說(shuō)列肢,可以把它看作是一個(gè)指針恰画,他指向當(dāng)前程序正在運(yùn)行的一行代碼。需要注意的是例书,他指向的是字節(jié)碼锣尉,不是你寫(xiě)的代碼!

java 虛擬機(jī)棧:線程私有,在創(chuàng)建線程時(shí)創(chuàng)建的决采,用來(lái)存儲(chǔ)棧幀自沧。是Java方法執(zhí)行的內(nèi)存模型。

  • 每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀树瞭,用于存儲(chǔ)局部變量表拇厢、操作數(shù)棧、動(dòng)態(tài)鏈接晒喷、方法出口等信息孝偎。
  • 每一個(gè)方法從調(diào)用直至執(zhí)行完成的過(guò)程,就對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過(guò)程凉敲。

局部變量表存放了編譯期可知的各種基本數(shù)據(jù)類型衣盾、對(duì)象引用類型和returnAddress類型寺旺,它所需的內(nèi)存空間在編譯期間完成分配。

  • 一般把Java內(nèi)存區(qū)分為堆內(nèi)存(Heap)和棧內(nèi)存(Stack)势决,其中『椬杷埽』指的是虛擬機(jī)棧,『堆』指的是Java堆果复。
  • 在Java虛擬機(jī)規(guī)范中陈莽,對(duì)這個(gè)區(qū)域規(guī)定了兩種異常狀況:
    如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常虽抄;
    如果虛擬機(jī)椬吒椋可動(dòng)態(tài)擴(kuò)展且擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存,將拋出OutOfMemoryError異常迈窟。

本地方法棧:跟JVM虛擬機(jī)棧比較類似私植,只不過(guò)它支持的是Native方法。

  • 在虛擬機(jī)規(guī)范中菠隆,對(duì)這個(gè)區(qū)域無(wú)強(qiáng)制規(guī)定兵琳,由具體的虛擬機(jī)自由實(shí)現(xiàn)。與虛擬機(jī)棧一樣骇径,本地方法棧區(qū)域也會(huì)拋出StackOverflowError和OutOfMemoryError異常躯肌。

java 堆:用于存放幾乎所有的對(duì)象實(shí)例和數(shù)組。

  • 被所有線程共享的一塊內(nèi)存區(qū)域破衔,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建清女。

在Java堆中,可能劃分出多個(gè)線程私有的分配緩沖區(qū)(Thread Local Allocation Buffer晰筛,TLAB)嫡丙,但無(wú)論哪個(gè)區(qū)域,存儲(chǔ)的都仍然是對(duì)象實(shí)例读第,進(jìn)一步劃分的目的是為了更好地回收內(nèi)存曙博,或者更快地分配內(nèi)存。

  • 是垃圾收集器管理的主要區(qū)域怜瞒,也被稱做“GC堆”父泳。
  • 是Java虛擬機(jī)所管理的內(nèi)存中最大的一塊。
  • 在Java虛擬機(jī)規(guī)范中吴汪,如果在堆中沒(méi)有內(nèi)存完成實(shí)例分配惠窄,且堆也無(wú)法再擴(kuò)展時(shí),將會(huì)拋出OutOfMemoryError異常漾橙。

方法區(qū):用于存儲(chǔ)已被虛擬機(jī)加載的類信息杆融、常量、靜態(tài)變量霜运、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)脾歇。與Java堆一樣蒋腮,是各個(gè)線程共享的內(nèi)存區(qū)域。

  • JVMS中起的別名叫non-heap(為了與Java堆區(qū)分開(kāi)來(lái))
  • 作用是存儲(chǔ) Java 類的結(jié)構(gòu)信息(代碼中:常量(static)介劫、靜態(tài)變量(static)徽惋、方法、JIT編譯后的部分?jǐn)?shù)據(jù))
  • JVMS 不要求該區(qū)域?qū)崿F(xiàn)自動(dòng)內(nèi)存管理座韵,但是商用 Java 虛擬機(jī)都能夠自動(dòng)管理該區(qū)域的內(nèi)存,主要是常量池回收和類類型卸載踢京,但是方法區(qū)的GC條件是相當(dāng)苛刻的誉碴。
  • 可能出現(xiàn) OutOfMemoryError 異常

那么方法區(qū)具體存儲(chǔ)了哪些東西呢?
(1)類型信息 :
   -- 這個(gè)類型的完整有效名
   -- 這個(gè)類的直接父類的完整有效名(除Object例外)
   -- 這個(gè)類型的修飾符(public absctract final)
   -- 這個(gè)類型的直接接口的游戲列表
   解釋下什么叫完整有效名:代碼中是 包名+ "." + 類名瓣距,但是類文件是"/"代替點(diǎn): com/gaiay/mebilecard/GroupDetail黔帕。
(2)運(yùn)行時(shí)常量池
   --全局共享
   --是方法區(qū)的一部分
   --作用是存儲(chǔ) Java 類文件常量池中的符號(hào)信息
   --可能出現(xiàn) OutOfMemoryError 異常
  在class文件中,有部分很重要的信息就是常量池蹈丸,用于存放在編譯期就生成好的各種字面量和符號(hào)引用成黄。這部分信息在類加載后被裝入方法區(qū)的運(yùn)行時(shí)常量池。Java虛擬機(jī)對(duì)class文件結(jié)構(gòu)是有非常嚴(yán)格的規(guī)定的逻杖,calss文件中的 常量池 以及其他信息奋岁,必須保證每個(gè)字節(jié)存儲(chǔ)哪種數(shù)據(jù)都必須與JVMS一致,才能被Java虛擬機(jī)認(rèn)可荸百、裝載和執(zhí)行闻伶,但是對(duì)于 運(yùn)行時(shí)常量池,JVMS并沒(méi)有細(xì)節(jié)上的約束,不同JVM廠商可以按照自己的需要去實(shí)現(xiàn)自己運(yùn)行時(shí)常量池够话,一般來(lái)說(shuō) 運(yùn)行時(shí)常量池除了保存class文件中描述的符號(hào)引用外也會(huì)把符號(hào)引用翻譯出來(lái)的直接引用一起存儲(chǔ)在運(yùn)行時(shí)常量池中蓝翰。 那么這里所說(shuō)的直接引用和間接引用指的是什么呢?好比當(dāng)前類為A.java , 里面引用了一個(gè)String str , 和一個(gè) 你自己寫(xiě)的類 B b, 那么a就是個(gè)直接引用女嘲, b就是間接引用 畜份。在編譯期,str在class文件中的描述可能就是String類似這樣的欣尼,而b就是類似 com.person.B.java (只是舉個(gè)栗子爆雹,不要當(dāng)真)。 然后在類加載時(shí)媒至,會(huì)根據(jù)com.person.B.java 在方法區(qū)符號(hào)表中解析出實(shí)際的B.java的真實(shí)地址顶别。      相比于class文件的常量池,既然叫做運(yùn)行時(shí)常量池拒啰,那么必然是有動(dòng)態(tài)性的驯绎。Java語(yǔ)言并不要求常量只能在編譯期間才能產(chǎn)生,在運(yùn)行時(shí)也可以通過(guò)代碼產(chǎn)生新的常量谋旦,并將它們放入到運(yùn)行時(shí)常量池當(dāng)中剩失。這種特性被開(kāi)發(fā)者利用最大的就是 String#intern() 屈尼。
(3)Field信息
    -- 域名
    -- 域類型
    -- 域修飾符(public, private, protected,static,final volatile, transient的某個(gè)子集)
(4)方法信息
    -- 方法名
    -- 方法的返回類型(或 void)
    -- 方法參數(shù)的數(shù)量和類型(有序的)
    -- 方法的修飾符(public, private, protected, static, final, synchronized, native, abstract的一個(gè)子集)
    -- 除了abstract和native方法外,其他方法還有保存方法的字節(jié)碼(bytecodes)操作數(shù)棧和方法棧幀的局部變量區(qū)的大小拴孤、異常表     
(5)static 變量(也叫類變量)
(6)final 常量

常量也會(huì)被保存在方法區(qū)中脾歧,同時(shí)也會(huì)復(fù)制一份到常量池中。保存在方法區(qū)中的常量是保存在使用他的類信息中演熟, 而static 變量是保存在 聲明 他的類信息中的鞭执。

(7)方法表
  JVMS并沒(méi)有聲明方法表一定要存在,他是Java虛擬機(jī)設(shè)計(jì)者為了提高方法的訪問(wèn)效率而實(shí)現(xiàn)的一種數(shù)據(jù)信息結(jié)構(gòu)芒粹,他是實(shí)現(xiàn)(1)中用來(lái)存儲(chǔ)類型信息的一部分兄纺,jvm對(duì)每個(gè)加載的非虛擬類(個(gè)人理解是非匿名類)的類型信息中都添加了一個(gè)方法表,方法表是一組對(duì)類實(shí)例方法的直接引用(包括從父類繼承的方法)化漆。jvm可以通過(guò)方法表快速激活實(shí)例方法估脆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市座云,隨后出現(xiàn)的幾起案子疙赠,更是在濱河造成了極大的恐慌,老刑警劉巖朦拖,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件圃阳,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡贞谓,警方通過(guò)查閱死者的電腦和手機(jī)限佩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)裸弦,“玉大人祟同,你說(shuō)我怎么就攤上這事±砀恚” “怎么了晕城?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窖贤。 經(jīng)常有香客問(wèn)我砖顷,道長(zhǎng),這世上最難降的妖魔是什么赃梧? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任滤蝠,我火速辦了婚禮,結(jié)果婚禮上授嘀,老公的妹妹穿的比我還像新娘物咳。我一直安慰自己,他們只是感情好蹄皱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布览闰。 她就那樣靜靜地躺著芯肤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪压鉴。 梳的紋絲不亂的頭發(fā)上崖咨,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天,我揣著相機(jī)與錄音油吭,去河邊找鬼击蹲。 笑死,一個(gè)胖子當(dāng)著我的面吹牛上鞠,可吹牛的內(nèi)容都是我干的际邻。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼芍阎,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缨恒?” 一聲冷哼從身側(cè)響起谴咸,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎骗露,沒(méi)想到半個(gè)月后岭佳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡萧锉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年珊随,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柿隙。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叶洞,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出禀崖,到底是詐尸還是另有隱情衩辟,我是刑警寧澤,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布波附,位于F島的核電站艺晴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏掸屡。R本人自食惡果不足惜封寞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仅财。 院中可真熱鬧狈究,春花似錦、人聲如沸满着。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至宁改,卻和暖如春缕探,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背还蹲。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工爹耗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人谜喊。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓潭兽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親斗遏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子山卦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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