????????jvm運行時數(shù)據(jù)區(qū)域,看標題多少有些生硬和晦澀询吴。換一種直白點兒的描述继榆,jvm內(nèi)存模型或jvm運行時內(nèi)存劃分。寫這篇文章的初衷是筆者本人在無數(shù)次面試過程中袖外,都不可避免的被問到這一話題史隆,因此,說總結(jié)也好曼验,說分享也罷泌射,還是沉淀一下相關(guān)的知識吧。作為一個工作2鬓照,3年的java程序員熔酷,總歸是繞不開這個話題的。有關(guān)虛擬機的理論和知識豺裆,也是一個初級程序員自我提升過程中必修的一門“課程”拒秘。
? ? ? ? 虛擬機內(nèi)存模型這個概念,你不一定聽過留储,但是“堆”翼抠、“棧”這兩個概念获讳,作為一個計算機相關(guān)專業(yè)畢業(yè)的程序員活喊,你一定或多或少的聽說過丐膝,或者在《數(shù)據(jù)結(jié)構(gòu)》,或者在《操作系統(tǒng)》偎肃,等等一些列專業(yè)課上,一定對其有所涉獵浑此。在畢業(yè)初期累颂,被問到虛擬機的內(nèi)存有幾塊兒凛俱,大部分同學能想到的也正是這兩個部分。當然蒲犬,這本身并沒有錯朱监,“堆”、“椩#”確實是虛擬機管理的最主要的兩塊兒內(nèi)存區(qū)域赫编。只不過奋隶,武斷的將虛擬機運行時數(shù)據(jù)區(qū)域劃分為 “堆”、“椢ㄐ溃” 兩部分,還是稍顯粗略躺苦。引用《深入理解java虛擬機》一書中的描述产还,對jvm運行時內(nèi)存模型做一個比較正式的劃分,如下圖所示:
jvm運行時數(shù)據(jù)區(qū)域劃分
大體上看來脐区,jvm運行時數(shù)據(jù)區(qū)域是由 (1)程序計數(shù)器、(2)虛擬機棧牛隅、 (3)本地方法棧 、(4)堆匕累、 (5)方法區(qū)這幾塊兒構(gòu)成的默伍。下面我們逐一說明一下這幾塊兒內(nèi)存區(qū)域具體都放了哪些東西及其詳細作用:
(1) 程序計數(shù)器:
? ? ? ? 程序計數(shù)器這個東西聽起來不是那么容易懂衰琐,其實相對來講炼蹦,它是最單純的一部分。大家都知道java 是半編譯半解釋型的編程語言狗热。我們寫出來的代碼源文件(.java)要經(jīng)過編譯階段生成字節(jié)碼文件(.class)虑省,再由虛擬機將字節(jié)碼文件解釋成 計算機能識別的底層機器指令來執(zhí)行。程序計數(shù)器可以看作是字節(jié)碼的行號指示器慷妙,字節(jié)碼指示器工作時就是通過改變這個程序計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。
? ? ? ? 由于java虛擬機的多線程模型是通過多個線程輪流切換并分配CPU執(zhí)行時間的方式來實現(xiàn)的虑啤,在任何一個確定的時刻架馋,一個處理器(現(xiàn)代多核處理器的情況下,指的是CPU的一個內(nèi)核)都只會執(zhí)行一條線程中的指令萍启。因此屏鳍,為了使線程切換后能恢復到正確的執(zhí)行位置,每條線程都需要一個獨立的程序計數(shù)器钓瞭。所以,程序計數(shù)器是線程私有的內(nèi)存區(qū)域堤结。由于該區(qū)域職責相對單一且占用內(nèi)存相對很小鸭丛,其是jvm中唯一一塊兒沒有定義任何內(nèi)存溢出錯誤(OutOfMemoryError)類型的區(qū)域。
(2) 虛擬機棧
? ? ? ? 與程序計數(shù)器類似瘾带,虛擬機棧也是線程私有的內(nèi)存區(qū)域穿挨。因此肴盏,它的生命周期同線程一致帽衙。虛擬機棧描述的是java方法執(zhí)行過程的內(nèi)存模型:每個方法在執(zhí)行的同時會創(chuàng)建一個棧幀贞绵,用于存儲局部變量表、操作數(shù)棧谴垫、動態(tài)鏈接母蛛、方法出口等信息。 每一個方法從開始執(zhí)行到執(zhí)行完成的過程彩郊,對應(yīng)著一個棧幀在虛擬機棧中入棧到出棧的過程秫逝。在java虛擬機規(guī)范中對這個區(qū)域規(guī)定了兩種異常:?
1、如果線程請求的棧深度大于虛擬允許的最大深度违帆,將會拋出StackOverFlowError。如下圖所示的畴,循環(huán)遞歸
循環(huán)遞歸
StackOverFlowError
2丧裁、虛擬機棧無法申請到足夠的內(nèi)存時班巩,就會拋出OutOfMemoryError 異常。
(3)本地方法棧
? ? ? ? 本地方法棧發(fā)揮的作用與虛擬機棧是非常相似的抱慌,它們的區(qū)別在于 :虛擬機棧是為執(zhí)行java方法(也就是字節(jié)碼)服務(wù)的,而本地方法則是為虛擬機調(diào)用的Native方法服務(wù)的强经。
(4)java堆
? ? ? ? 對于大多數(shù)應(yīng)用來說寺渗,java堆(java heap)是java虛擬機中管理的內(nèi)存中最大的一塊兒兰迫。java堆是被所有線程共享的一塊兒內(nèi)存區(qū)域炬称,在虛擬機啟動時就被創(chuàng)建。此內(nèi)存區(qū)域的唯一作用就是存放對象實例据德,幾乎所有的對象實例都在這里分配內(nèi)存跷车。因此,堆也是垃圾收集器管理的主要區(qū)域善玫∶芮浚基于現(xiàn)代垃圾收集器的分代收集算法,堆還可以被進一步劃分為 年輕代和老年代誓斥。再細致一些,年輕代還可以被細分為 eden 和from survivor毕谴、to survivor空間等距芬。如果在堆中沒有足夠的內(nèi)存用以分配,且無法申請到更多的內(nèi)存舀武,就會拋出 OutOfMemoryError異常离斩。
無限new 對象出來
堆內(nèi)存溢出
(5)方法區(qū)
俗稱 “永久代”跛梗,與堆一樣,也是多個線程共享的內(nèi)存區(qū)域核偿。它用于存儲已經(jīng)被虛擬機加載的類信息、常量轰绵、靜態(tài)變量、即時編譯器編譯后的代碼等左腔,當方法區(qū)無法滿足內(nèi)存分配需求時翔悠,將拋出OutOfMemoryError異常野芒。
最后,總結(jié)一下狞悲,線程私有的內(nèi)存區(qū)域:程序計數(shù)器、虛擬機棧丹拯,本地方法棧荸恕;多個線程共享的內(nèi)存區(qū)域:堆,方法區(qū)咬像。垃圾收集關(guān)注的區(qū)域:堆生宛,方法區(qū)。