你還記得嗎雪情?你還記得嗎?你還記得嗎你辣?從來沒有記住過巡通,又何來忘記呢!
內(nèi)存結(jié)構(gòu)可以說是面試100%會(huì)出現(xiàn)的舍哄!為了應(yīng)付面試宴凉,趕緊百度、看書表悬,結(jié)果面試官問的深一點(diǎn)就嗝屁了弥锄!還不如說不會(huì)呢,可是這么基礎(chǔ)的知識(shí)點(diǎn)都不會(huì)蟆沫,所謂的會(huì)也可能是理論層面的籽暇,我在網(wǎng)上看多了很多相關(guān)的文章,互相印證饭庞,大部分的文章都是理論戒悠,理論還是理論。沒錯(cuò)理論是實(shí)踐的基礎(chǔ)舟山,可是知行合一才是完整的绸狐。廢話不多說了,下面進(jìn)入正題累盗。
內(nèi)存區(qū)域的劃分:
共享區(qū)域:堆六孵、方法區(qū)
私有區(qū)域:程序計(jì)數(shù)器、棧幅骄、本地方法棧
注:1.8開始沒有單獨(dú)的方法區(qū)劫窒,而是在堆中分配一塊區(qū)域作為方法區(qū),通過命令查看內(nèi)存情況可知拆座,真的沒有單獨(dú)方法區(qū)
1:程序計(jì)數(shù)器
? ? ? 計(jì)數(shù)器到底記得是什么數(shù)呢主巍?當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器冠息。解釋器就是通過計(jì)數(shù)器來控制分支、循環(huán)孕索、跳轉(zhuǎn)逛艰、異常處理、線程恢復(fù)等搞旭,為了保證每個(gè)線程正確執(zhí)行散怖,計(jì)數(shù)器是每個(gè)線程私有的。在形象一點(diǎn)就是查看class文件肄渗,code對(duì)應(yīng)的每一行都是指令镇眷,計(jì)數(shù)器就是要記錄當(dāng)前棧正在執(zhí)行的指令行,當(dāng)線程切換后繼續(xù)執(zhí)行時(shí)翎嫡,從上一次的指令行繼續(xù)執(zhí)行欠动,
如果執(zhí)行native方法,則計(jì)數(shù)器的值為空(undefined)
程序計(jì)數(shù)器特點(diǎn):
? ? 線程私有惑申、生命周期和線程相同具伍、無OutOfMemoryError異常
2:虛擬機(jī)棧
? ? 線程私有的,和程序計(jì)數(shù)器的生命周期相同圈驼,虛擬機(jī)棧描述的是java方法執(zhí)行的內(nèi)存模型人芽,每個(gè)方法執(zhí)行時(shí)會(huì)創(chuàng)建一個(gè)棧幀。棧幀主要保存局部變量表绩脆、操作數(shù)棧萤厅、動(dòng)態(tài)鏈接、方法出口,局部變量表存放了編譯期可知的各種基本類型衙伶、對(duì)象引用(指針、句柄害碾、對(duì)象的位置)矢劲、returnAddress類型(指向一條字節(jié)碼指令)。線程請求的棧深度大于虛擬機(jī)允許的深度拋出StackOverFlowError(遞歸調(diào)用很容易拋出)慌随,如果虛擬機(jī)支持?jǐn)U展空間芬沉,當(dāng)無法申請到足夠空間時(shí)拋出OutOfMemoryError(如果堆內(nèi)存快用盡的時(shí)候,申請棧內(nèi)存就會(huì)拋出)
虛擬機(jī)棧的特點(diǎn):
? 線程私有阁猜、生命周期和線程相同丸逸、拋出StackOverFlowError和OutOfMemoryError、存放內(nèi)容(局部變量表剃袍、操作數(shù)黄刚、動(dòng)態(tài)鏈接、方法出口)
3:本地方法棧
? 和虛擬機(jī)棧的作用相同民效,只不過執(zhí)行的是本地方法憔维,而非java方法
4:堆
? 所有對(duì)象的實(shí)例和數(shù)據(jù)都要在堆上分配,堆還可以細(xì)分為新生代涛救、老年代、Eden空間业扒、From Survivor空間检吆、To Survivor空間,從內(nèi)存分配角度可以劃出多個(gè)線程私有的分配緩沖區(qū)TLAB程储,無論怎么劃分和存在內(nèi)容無關(guān)蹭沛,仍然是實(shí)例,劃分的目的就是為了更好的回收內(nèi)存章鲤,或者更快的分配內(nèi)存摊灭。物理空間可以不連續(xù),但是邏輯空間要連續(xù)咏窿,如果無法擴(kuò)展拋出OutOfMemoryError斟或,可通過-Xmx -Xms 控制,無法擴(kuò)展拋出OutOfMemoryError
源碼:
? ? ? ? byte[] allocation1, allocation2, allocation3,allocation4;
? ? ? ? allocation1 = new byte[1 * _1MB];
? ? ? ? allocation2 = new byte[2 * _1MB];
? ? ? ? allocation3 = new byte[3 * _1MB];
? ? ? ? allocation4 = new byte[4 * _1MB];
打印內(nèi)存情況
Heap Parameters:
Gen 0:? eden [0x04800000,0x04c28068,0x05000000) space capacity = 8388608, 51.95436477661133 used
? from [0x05100000,0x0517b108,0x05200000) space capacity = 1048576, 48.072052001953125 used
? to? [0x05000000,0x05000000,0x05100000) space capacity = 1048576, 0.0 usedInvocations: 1
Gen 1:? old? [0x05200000,0x05800030,0x05c00000) space capacity = 10485760, 60.000457763671875
可知內(nèi)存的地址范圍是0x04800000-0x05c00000
上圖中的4個(gè)byte數(shù)組對(duì)應(yīng)的內(nèi)存地址為0x04800000集嵌、0x05500050萝挤、0x05300010、0x05200000根欧,那么就足以說明這四個(gè)對(duì)象存儲(chǔ)在堆里
堆的特點(diǎn):共享內(nèi)存怜珍、生命周期和虛擬機(jī)相同、拋出OutOfMemoryError凤粗,保存所有的new的實(shí)例
5:方法區(qū)
? ? 線程共享的內(nèi)存區(qū)域酥泛,用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量嫌拣、靜態(tài)變量柔袁、即時(shí)編譯器編譯后的代碼數(shù)據(jù),虛擬機(jī)規(guī)范描述方法區(qū)為的一個(gè)邏輯部分异逐,別名非堆捶索,主要是和堆區(qū)分開。無法擴(kuò)展拋OutOfMemoryError,關(guān)于類的具體細(xì)節(jié)會(huì)有專門章節(jié)
方法區(qū)特點(diǎn):
共享內(nèi)存灰瞻、生命周期和虛擬機(jī)相同腥例、拋出OutOfMemoryError,保存類信息酝润、常量燎竖、靜態(tài)變量、即時(shí)編譯器編譯后的代碼數(shù)據(jù)
6:常量池
運(yùn)行時(shí)常量池是方法區(qū)的一部分要销,class文件中除了有版本构回、字段、方法、接口信息外還有一項(xiàng)信息是常量池捐凭,用于存放編譯后生成的字面量和引用拨扶,這部分內(nèi)容將在類加載后進(jìn)入方法區(qū)的運(yùn)行時(shí)常量池中存放。運(yùn)行過程中新的常量也可以放入常量池茁肠,允許擴(kuò)展,無法擴(kuò)展拋OutOfMemoryError
常量池特點(diǎn):
共享內(nèi)存患民、生命周期和虛擬機(jī)相同、拋出OutOfMemoryError垦梆,保存常量