距離上次文章已經(jīng)半個多月了泵肄,一來是工作實(shí)在是忙不開腐巢,二來是偷懶了玄括!近日,看到一個面試題目遭京,就是描述一下JVM內(nèi)存模型泞莉,故在此總結(jié)一番鲫趁,希望讀者能夠更好的理解JVM內(nèi)存模型捺弦。
1.JVM內(nèi)存模型簡介
JVM定義了不同運(yùn)行時數(shù)據(jù)區(qū),他們是用來執(zhí)行應(yīng)用程序的幽崩。某些區(qū)域隨著JVM啟動及銷毀寞钥,另外一些區(qū)域的數(shù)據(jù)是線程性獨(dú)立的,隨著線程創(chuàng)建和銷毀蹄溉。jvm內(nèi)存模型總體架構(gòu)圖如下:(摘自oracle官方網(wǎng)站)
JVM在執(zhí)行Java程序時您炉,會把它管理的內(nèi)存劃分為若干個的區(qū)域,每個區(qū)域都有自己的用途和創(chuàng)建銷毀時間棉胀。如下圖所示冀膝,可以分為兩大部分,線程私有區(qū)和共享區(qū)麻掸。下圖是根據(jù)自己理解畫的一個JVM內(nèi)存模型架構(gòu)圖:
安利:上圖是利用在線畫圖工具processon赐纱,我也是剛上手,個人感覺還不錯诚隙,各種圖例都有淫痰,在此安利一下!
2.內(nèi)存模型
2.1.線程私有區(qū)
2.1.1 程序計數(shù)器
當(dāng)同時進(jìn)行的線程數(shù)超過CPU數(shù)或其內(nèi)核數(shù)時籽孙,就要通過時間片輪詢分派CPU的時間資源,不免發(fā)生線程切換犯建。這時,每個線程就需要一個屬于自己的計數(shù)器來記錄下一條要運(yùn)行的指令竿开。如果執(zhí)行的是JAVA方法,計數(shù)器記錄正在執(zhí)行的java字節(jié)碼地址否彩,如果執(zhí)行的是native方法嗦随,則計數(shù)器為空。
2.1.2 虛擬機(jī)棧
線程私有的贴浙,與線程在同一時間創(chuàng)建署恍。管理JAVA方法執(zhí)行的內(nèi)存模型。每個方法執(zhí)行時都會創(chuàng)建一個楨棧來存儲方法的的變量表盯质、操作數(shù)棧、動態(tài)鏈接方法般婆、返回值朵逝、返回地址等信息乡范。棧的大小決定了方法調(diào)用的可達(dá)深度(遞歸多少層次,或嵌套調(diào)用多少層其他方法渠脉,-Xss參數(shù)可以設(shè)置虛擬機(jī)棧大小)芋膘。棧的大小可以是固定的,或者是動態(tài)擴(kuò)展的臂拓。如果請求的棧深度大于最大可用深度,則拋出stackOverflowError胶惰;如果棧是可動態(tài)擴(kuò)展的霞溪,但沒有內(nèi)存空間支持?jǐn)U展,則拋出OutofMemoryError坊饶。
使用jclasslib工具可以查看class類文件的結(jié)構(gòu)殴蓬。下圖為棧幀結(jié)構(gòu)圖:
2.1.3 本地方法棧
與虛擬機(jī)棧作用相似。但它不是為Java方法服務(wù)的根蟹,而是本地方法(C語言)糟秘。由于規(guī)范對這塊沒有強(qiáng)制要求,不同虛擬機(jī)實(shí)現(xiàn)方法不同散庶。
2.2.線程共享區(qū)
此區(qū)域是用來存儲被各線程共享的數(shù)據(jù)的。
2.2.1 方法區(qū)
線程共享的悲龟,用于存放被虛擬機(jī)加載的類的元數(shù)據(jù)信息冰寻,如常量、靜態(tài)變量和即時編譯器編譯后的代碼轻腺。若要分代划乖,算是永久代(老年代),以前類大多“static”的琴庵,很少被卸載或收集仰美,現(xiàn)回收廢棄常量和無用的類筒占。其中運(yùn)行時常量池存放編譯生成的各種常量蜘犁。(如果hotspot虛擬機(jī)確定一個類的定義信息不會被使用,也會將其回收奏窑。回收的基本條件至少有:所有該類的實(shí)例被回收埃唯,而且裝載該類的ClassLoader被回收)
2.2.2 堆
存放對象實(shí)例和數(shù)組鹰晨,是垃圾回收的主要區(qū)域,分為新生代和老年代漠趁。剛創(chuàng)建的對象在新生代的Eden區(qū)中忍疾,經(jīng)過GC后進(jìn)入新生代的S0區(qū)中,再經(jīng)過GC進(jìn)入新生代的S1區(qū)中卤妒,15次GC后仍存在就進(jìn)入老年代。這是按照一種回收機(jī)制進(jìn)行劃分的共缕,不是固定的士复。若堆的空間不夠?qū)嵗峙洌瑒tOutOfMemoryError蜓萄。
Young Generation 即圖中的Eden + From Space(s0) + To Space(s1)
Eden 存放新生的對象
Survivor Space 有兩個澄峰,存放每次垃圾回收后存活的對象(s0+s1)
Old Generation Tenured Generation 即圖中的Old Space
主要存放應(yīng)用程序中生命周期長的存活對象
2.3堆和棧的區(qū)別
棧是運(yùn)行時單位辟犀,代表著邏輯绸硕,內(nèi)含基本數(shù)據(jù)類型和堆中對象引用玻佩,所在區(qū)域連續(xù)席楚,沒有碎片;堆是存儲單位烦秩,代表著數(shù)據(jù),可被多個棧共享(包括成員中基本數(shù)據(jù)類型兜蠕、引用和引用對象)抛寝,所在區(qū)域不連續(xù),會有碎片盗舰。
2.3.1功能不同
棧內(nèi)存用來存儲局部變量和方法調(diào)用,而堆內(nèi)存用來存儲Java中的對象郊霎。無論是成員變量爷绘,局部變量,還是類變量土至,它們指向的對象都存儲在堆內(nèi)存中。
2.3.2共享性不同
棧內(nèi)存是線程私有的骡苞。
堆內(nèi)存是所有線程共有的楷扬。
2.3.3異常錯誤不同
如果棧內(nèi)存或者堆內(nèi)存不足都會拋出異常。
椂阒辏空間不足:java.lang.StackOverFlowError。
堆空間不足:java.lang.OutOfMemoryError霜定。
2.3.4空間大小
棧的空間大小遠(yuǎn)遠(yuǎn)小于堆的。
2.4參考鏈接
http://www.cnblogs.com/AloneSword/p/4262255.html
http://www.reibang.com/p/6ff6bdb22439