開篇閑話:
王侯將相皆有封地饵婆,大小根據爵位高低而不同,等級森嚴咐鹤。在計算機世界里龄捡,大boss(操作系統(tǒng))很公平,給大家(進程)都分配了同樣的內存大锌对荨(雖然這也是個假象)聘殖。我們的主角JVM出生的那天,大boss跟他說行瑞,你有4G的宅基地(內存空間)可以使用奸腺,讓他好好想想怎么用,用的不好血久,年輕人突照,你將永無出頭之日啊氧吐!
小主JVM雖然年紀小讹蘑,但是思考的深度不亞于他的爸爸 James Gosling末盔。把自家的一畝三分地管理地不僅秩序井然,還年年碩果累累座慰。
預備知識:認識內存
1陨舱、內存是存放數據與指令的地方,cpu從緩存和內存中獲取指令和數據執(zhí)行程序版仔。
2游盲、JVM的內存區(qū)域是操作系統(tǒng)分配的一段內存空間,不能拋開計算機內存管理單看JVM的內存管理蛮粮。(了解操作系統(tǒng)益缎、cpu、主存然想、I/O設備如何運行與協作很重要莺奔,它能讓你總攬全局而非以偏概全)
3、JVM屏蔽了各操作系統(tǒng)的指令集的區(qū)別变泄,程序的數據和指令加載到內存中令哟,通過JVM運行,最終也是通過JVM將這些指令轉化為機器語言(比如匯編語言)杖刷,由cpu中的運算器和寄存器等進行運算。
1驳癌、計算機內存模型
現在的計算機模型來自于馮·諾伊曼計算機結構滑燃,它解決了人類運算思維的機器實現和延展,可進行大量的復雜運算颓鲜,同時也存在諸多的問題(比如數據同步的問題等)透绩。內存在計算機中扮演的角色是指令和數據的存儲鲫惶,與cpu合作完成程序運行。假設需要計算1+1=?冠息,內存中的狀態(tài)可簡化為:
①內存中存放程序指令MOVE[504]EAX(將地址為504處的內存值復制到寄存器EAX中)、MOVE[505]EBX炼鞠、ADD EAX EBX(將寄存器中EAX和EBX中的值相加放在EBX)戈擒;
②內存的每個存儲單元存儲的是指令還是值,由程序自己解析
2艾扮、內存的運行效率
類比廚師做菜既琴,需要食材,食材可來源于超級市場泡嘴、蔬果市場或者便利店甫恩,市場儲藏的位置遠近決定了廚師做出菜肴的效率。類似的酌予,程序運行需要數據磺箕,程序的數據在文件奖慌、輸入設備、內存松靡、緩存中简僧,各個設備的工作原理的差別,導致運行的效率區(qū)別天差地別:
cpu讀取數據優(yōu)先從緩存中讀然骼А(一級涎劈、二級、三級)阅茶,如果沒有就到內存中讀取蛛枚。如果cpu的延遲時間是1s,則內存的延遲為100-360s脸哀,速度很快蹦浦。數據在緩存和內存中均不存在,需要從硬盤中讀取撞蜂,那就要等上1-12個月盲镶。內存很重要的一個職責就是做為硬盤的緩沖區(qū),大大提升運行效率蝌诡。
JVM內存模型及管理機制
1溉贿、運行時數據區(qū)
①程序計數器:
程序計數器(program counter register)是一塊較小的存儲空間,它是每個線程私有的內存區(qū)域浦旱,主要的作用是記住當前程序執(zhí)行到哪條指令宇色,以便在線程切換后可以準確的繼續(xù)執(zhí)行指令。
怎么記錄呢颁湖,記錄什么呢宣蠕?其實很簡單,就是記錄指令的內存地址甥捺。
②java虛擬機棧
虛擬機棧屬于線程私有抢蚀,與線程同生共死。每當調用一個方法時镰禾,即在虛擬機棧中創(chuàng)建一個函數棧幀:
局部變量表:
1皿曲、存放編譯期可知的各種基本類型(boolean,byte吴侦,char谷饿,short,int妈倔,long博投,float,double)盯蝴、對象引用類型(指向對象地址起始位置的指針或代表對象的句柄)毅哗;
2听怕、存儲的單元稱為slot,大小為32位虑绵;
3尿瞭、數組結構,通過索引訪問翅睛;
4声搁、局部變量表的空間大小(slot數量)在編譯期便確定下來捕发。
操作數棧:
1疏旨、被稱為“基于棧的執(zhí)行引擎”
2、操作數棧是執(zhí)行字節(jié)碼指令時扎酷,進行運算的單元檐涝;
3、數組結構法挨,通過棧操作(壓棧和出棧)來訪問谁榜,下面的代碼展示了0與1相加時操作數棧運行的字節(jié)碼指令:
iload_0 // 將int類型的數字0壓入棧中
iload_1 // 將int類型的1壓入棧中
iadd // 將剛才壓入的兩個數字pop出去,相加凡纳,壓入棧中
istore_2 // 將值pop到局部變量表中slot為2的地方
③方法區(qū):
各個線程共享的內存區(qū)域窃植,用于存儲已經被加載的類信息、常量荐糜、靜態(tài)變量巷怜、即時編譯器編譯后的代碼等數據。
④方法區(qū)中的運行時常量池
java的Class文件中包含類的版本狞尔、字段丛版、方法巩掺、接口等的描述信息偏序,還有一項:常量池,用于存放編譯期生成的字面量和符號引用胖替。這部分內容將在類加載到方法區(qū)后研儒,存放在方法區(qū)的運行時常量池。
運行時常量池的存在是因為常量池的內容是可以動態(tài)改變的独令,不僅僅是編譯期確定的常量池內容端朵。
⑤對象的內存布局
1、對象可不是我們平常畫一個圓圈燃箭,標注“對象”兩個字那么簡單冲呢。它是用來存儲運行時數據的地方;
2招狸、對象分配的內存空間中主要包含三個部分:對象頭敬拓、實例數據和對齊填充(包含的信息如圖所示)邻薯;
3、需要特別說明的是“實例數據”乘凸,這部分存儲的是有效信息厕诡,就是在類代碼中定義的字段內容(包含成員變量和局部變量,這是我個人的理解营勤,待探討)灵嫌,包含繼承自父類的字段。
⑥如何找到對象
我們在函數棧幀中會用reference代表對象的類型葛作,通過refrence來定位對象寿羞。在jvm規(guī)范中并沒有明確定義reference,現在主流的實現方式有兩種:
1进鸠、指針:reference指向堆中對象稠曼,指針指向方法區(qū)的對象類型數據;
2客年、句柄:堆中劃分一片內存做為句柄池霞幅,reference存儲的是對象的句柄地址,句柄中包含對象實例數據和類型數據的地址
最后量瓜,上張圖司恳,縱覽一下全局: