jvm內(nèi)存共分為虛擬機(jī)棧,堆 ,方法區(qū),程序計(jì)數(shù)器,本地方法區(qū)五個(gè)部分。
程序計(jì)數(shù)器(線程私有):
是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器,每條線程都要有一個(gè)獨(dú)立的程序計(jì)數(shù)器,這類內(nèi)存也稱為“線程私有”的內(nèi)存。
正在執(zhí)行java方法的話,計(jì)數(shù)器記錄的是虛擬機(jī)字節(jié)碼指令的地址(當(dāng)前指令的地址)。如果還是Native方法,則為空。
這個(gè)內(nèi)存區(qū)域是唯一一個(gè)在虛擬機(jī)中沒有規(guī)定任何OutOfMemoryError情況的區(qū)域。
Java虛擬機(jī)棧(線程私有):
也是線程私有的。
每個(gè)方法在執(zhí)行的時(shí)候會(huì)創(chuàng)建一個(gè)棧幀,存儲(chǔ)了局部變量表,操作數(shù)棧,動(dòng)態(tài)連接,方法返回地址等。
每個(gè)方法從調(diào)用到執(zhí)行完畢,對(duì)應(yīng)一個(gè)棧幀在虛擬機(jī)棧中的入棧和出棧。
通常所說的棧,一般是指虛擬機(jī)棧中的局部變量表部分。
局部變量表所需的內(nèi)存在編譯期間完成分配。
如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,則StackOverflowError。
如果虛擬機(jī)??梢詣?dòng)態(tài)擴(kuò)展,擴(kuò)展到無法申請(qǐng)足夠的內(nèi)存,則OutOfMemoryError。
本地方法棧(線程私有):
和虛擬機(jī)棧類似,主要為虛擬機(jī)使用到的Native方法服務(wù)。
也會(huì)拋出StackOverflowError和OutOfMemoryError。
Java堆(線程共享):
被所有線程共享的一塊內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,用于存放對(duì)象實(shí)例。
堆可以按照可擴(kuò)展來實(shí)現(xiàn)(通過-Xmx和-Xms來控制)
當(dāng)堆中沒有內(nèi)存可以分配給實(shí)例,也無法再擴(kuò)展時(shí),則拋出OutOfMemoryError異常。
方法區(qū)(線程共享):
被所有線程共享的一塊內(nèi)存區(qū)域。
用于存儲(chǔ)已被虛擬機(jī)加載的類信息,常量,靜態(tài)變量等。
這個(gè)區(qū)域的內(nèi)存回收目標(biāo)主要針對(duì)常量池的回收和對(duì)類型的卸載。
當(dāng)方法區(qū)無法滿足內(nèi)存分配需求時(shí),則拋出OutOfMemoryError異常。
在HotSpot虛擬機(jī)中,用永久代來實(shí)現(xiàn)方法區(qū),將GC分代收集擴(kuò)展至方法區(qū),但是這樣容易遇到內(nèi)存溢出的問題。
JDK1.7中,已經(jīng)把放在永久代的字符串常量池移到堆中。
JDK1.8撤銷永久代,引入元空間。
運(yùn)行時(shí)常量池:
是方法區(qū)的一部分,用于存放編譯期生成的各種字面量和符號(hào)引用。
當(dāng)常量池?zé)o法再申請(qǐng)到內(nèi)存時(shí),則拋出OutOfMemoryError異常。
直接內(nèi)存:
不是運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,但也可能拋出OutOfMemoryError異常。
在JDK1.4中新加入的NOI類,引入了一種基于通道與緩沖區(qū)的I/O方式,它可以使用Native函數(shù)直接分配堆外內(nèi)存,
然后通過一個(gè)存儲(chǔ)在Java堆中的DirectByteBuffer對(duì)象作為這塊內(nèi)存的引用進(jìn)行操作