java不像c語(yǔ)言一樣垦页,需要手動(dòng)分配和釋放內(nèi)存娘锁,java的內(nèi)存管理都是由jvm自動(dòng)處理的钮莲,那么是不是我們就不需要了解java的內(nèi)存管理了呢照藻?不袜啃,機(jī)器處理并不能保證避免內(nèi)存泄露和溢出的出現(xiàn),因此學(xué)習(xí)好內(nèi)存管理是我們解決內(nèi)存泄露和溢出等問(wèn)題的知識(shí)基礎(chǔ)幸缕。第一步先來(lái)學(xué)習(xí)運(yùn)行時(shí)數(shù)據(jù)區(qū)域群发。
如下圖晰韵,這是jvm對(duì)管理的內(nèi)存的一個(gè)劃分,分為方法區(qū)熟妓、堆雪猪、虛擬機(jī)棧、本地方法棧和程序計(jì)數(shù)器這五個(gè)區(qū)域起愈,每個(gè)區(qū)域有著自己的用途只恨,他們創(chuàng)建和被銷(xiāo)毀的時(shí)間也不同。
runtime_area.png
程序計(jì)數(shù)器(program counter register)
- 線程私有的一塊內(nèi)存空間告材,每個(gè)線程各有一個(gè)程序計(jì)數(shù)器坤次,互不影響。
- 可以看作當(dāng)前線程執(zhí)行的字節(jié)碼的行號(hào)指示器斥赋,字節(jié)碼解釋器通過(guò)程序計(jì)數(shù)器來(lái)獲取下一條需執(zhí)行的字節(jié)碼指令,分支产艾、循環(huán)疤剑、跳轉(zhuǎn)、異常處理闷堡、線程恢復(fù)都離不開(kāi)這個(gè)計(jì)數(shù)器
- 若執(zhí)行java方法隘膘,計(jì)數(shù)器記錄字節(jié)碼指令的地址;若執(zhí)行native方法杠览,計(jì)數(shù)器則為空
- 此內(nèi)存區(qū)域是唯一沒(méi)OutOfMermoryError的區(qū)域
虛擬機(jī)棧
- 線程私有的弯菊,生命周期和線程相同
- 每個(gè)方法都會(huì)創(chuàng)建一個(gè)棧幀來(lái)存儲(chǔ)局部變量表、操作數(shù)棧踱阿、動(dòng)態(tài)連接管钳、方法出口等信息。其中局部變量表存放了編譯期可知的基本數(shù)據(jù)類(lèi)型和對(duì)象引用(不是對(duì)象)
- 局部變量表在編譯期就會(huì)完成內(nèi)存分配软舌,因此在運(yùn)行期局部變量表的大小時(shí)固定的
- 若請(qǐng)求的棧的大小超過(guò)虛擬機(jī)允許的最大內(nèi)存才漆,就會(huì)拋出StackOverFlowException異常;若虛擬機(jī)椃鸬悖可以動(dòng)態(tài)擴(kuò)展醇滥,擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存,會(huì)拋出OutOfMermoryError異常
本地方法棧
- 與虛擬機(jī)棧類(lèi)似超营,有的虛擬機(jī)(如 sun Hotspot虛擬機(jī))將本地方法棧和虛擬機(jī)棧合二為一
- 本地方法棧為native方法服務(wù)鸳玩,而虛擬機(jī)棧為java方法服務(wù)
- 會(huì)出現(xiàn)的異常和虛擬機(jī)棧一樣
堆
- 所有線程共享的最大的一塊內(nèi)存。
- 在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建演闭,可通過(guò)jvm參數(shù) -Xmx和-Xms 來(lái)設(shè)置堆內(nèi)存大小
- 幾乎所有的對(duì)象實(shí)例和數(shù)組都在堆上存放不跟。逃逸分析這一技術(shù)則使得對(duì)象不盡都分配在堆上
- 堆進(jìn)一步劃分可分為新生代和老年代,新生代又可分為Eden空間船响、From Survivor和To Survivor躬拢。這些劃分都是為了 GC(garbage collection)躲履,后面會(huì)講到GC
方法區(qū)
- 線程共享
- 存儲(chǔ)虛擬機(jī)加載的類(lèi)信息、常量聊闯、靜態(tài)變量和即時(shí)編譯器編譯后的代碼等數(shù)據(jù)
- 當(dāng)方法區(qū)無(wú)法滿足內(nèi)存分配的需求時(shí)工猜,會(huì)拋出OutOfMermoryError異常
運(yùn)行時(shí)常量池
- 運(yùn)行時(shí)常量池jdk1.6包括1.6之前位于方法區(qū),1.7以后位于堆中
- class文件中除了有類(lèi)的版本菱蔬、字段篷帅、方法、接口等描述信息外拴泌,還有一項(xiàng)信息是常量池魏身,用于存放編譯期生成的各種字面量和符號(hào)引用,這部分內(nèi)容將在類(lèi)加載后存放于方法區(qū)的運(yùn)行時(shí)常量池蚪腐。
- 具有動(dòng)態(tài)性箭昵。也可在運(yùn)行期中加入運(yùn)行時(shí)常量池,如String的intern方法回季。
- 內(nèi)存不夠時(shí)會(huì)拋出OutOfMermoryError異常
直接內(nèi)存
- 并不是虛擬機(jī)規(guī)范中定義的區(qū)域家制,但被頻繁使用,也可能出現(xiàn)OutOfMermoryError異常
- JDK1.4引入了NIO泡一,引入了一種基于通道和緩沖區(qū)的IO方式颤殴,可以使用native函數(shù)庫(kù)分配堆外內(nèi)存,java堆可以通過(guò)DirectByteBuffer對(duì)象來(lái)操作這塊內(nèi)存鼻忠,提高了性能涵但。
- 受本機(jī)內(nèi)存限制,有時(shí)忽略了這塊內(nèi)存帖蔓,導(dǎo)致各內(nèi)存區(qū)域大于物理內(nèi)存限制矮瘟,從而出現(xiàn)OutOfMermoryError異常