java與C++之間有一堵由內(nèi)存動態(tài)分配和垃圾收集技術(shù)所圍成的高墻辫诅,墻外的人想進(jìn)去哺哼,墻里面的人想出來转质。
一园欣、JVM把內(nèi)存分為若干個不同的區(qū)域,有的區(qū)隨著JVM進(jìn)程的啟動而存在休蟹,有些區(qū)域則依賴用戶線程的啟動和結(jié)束而建立銷毀沸枯。JVM的運(yùn)行時(shí)數(shù)據(jù)區(qū)域包括以下幾個部分:1、程序計(jì)數(shù)器鸡挠;2辉饱、java虛擬機(jī)棧;3拣展、本地方法棧彭沼;4、java堆备埃;5姓惑、方法區(qū)。另外還有1按脚、運(yùn)行時(shí)常量池于毙;2、直接內(nèi)存辅搬。
1唯沮、程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它是當(dāng)前線程所執(zhí)行的字節(jié)碼行號指示器堪遂,字節(jié)碼解釋器就是通過改變這個計(jì)數(shù)器的值來選取下一條的指令介蛉,比如:分支、循環(huán)溶褪、跳轉(zhuǎn)币旧、異常處理、線程恢復(fù)等基礎(chǔ)功能都需要依賴計(jì)數(shù)器猿妈。每條線程都有一個獨(dú)立的計(jì)數(shù)器吹菱,所以這塊內(nèi)存是線程私有的區(qū)域。如果線程正在執(zhí)行java方法彭则,那么計(jì)數(shù)器記錄的是字節(jié)碼指令的地址鳍刷,如果正在執(zhí)行Native方法,則為空俯抖。此區(qū)域不存在OutOfMemoryError输瓜;
2、java虛擬機(jī)棧(Stack)也是線程私有的,他的生命周期和線程相同前痘,改區(qū)域是java方法的內(nèi)存模型,方法在執(zhí)行時(shí)會創(chuàng)建一個棧幀(有局部變量表担忧、操作數(shù)棧芹缔、動態(tài)鏈接、方法出棧等信息)瓶盛。如果線程請求的深度太大就拋StackOverFlowError異常最欠,如果擴(kuò)展時(shí)無法申請到足夠的內(nèi)存就拋OutOfMemoryError異常;
3惩猫、本地方法棧和虛擬機(jī)棧非常類似芝硬,只不過虛擬機(jī)棧是為java方法(也就是字節(jié)碼)服務(wù)的,而本地方法棧是為Native方法服務(wù)的轧房。拋出異常情況也和虛擬機(jī)棧一樣拌阴;
4、java堆(heap)是所有線程共享的一塊區(qū)域奶镶,也是JVM管理的內(nèi)存中最大的一塊迟赃,在虛擬機(jī)啟動時(shí)就已經(jīng)創(chuàng)建。此區(qū)域的唯一目的就是存放對象實(shí)例厂镇。所有的對象實(shí)例以及數(shù)組都在堆上分配纤壁。也是垃圾回收的主要區(qū)域。內(nèi)部可細(xì)分為:新生代和老年代捺信。更細(xì)一點(diǎn)的劃分就是:Eden酌媒、From Survive、To Survive等。擴(kuò)展時(shí)申請不到足夠的內(nèi)存就拋OutOfMemoryError異常。
5翁巍、方法區(qū)(Non-Heap)也是所有線程共享的的區(qū)域钥庇,它用于儲存已被虛擬機(jī)加載的類信息、常量插勤、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。HotSpot虛擬機(jī)把堆中的永久代作為方法區(qū)的(JDK1.7后把字符串常量池移除永久代)舅世,對于其他虛擬機(jī)是不存在永久代概念的。擴(kuò)展時(shí)申請不到足夠的內(nèi)存就拋OutOfMemoryError異常奇徒。
6雏亚、運(yùn)行時(shí)常量池是方法區(qū)的一部分,存放Class文件中的常量池和運(yùn)行期間產(chǎn)生的常量(String類的intern()方法)摩钙。擴(kuò)展時(shí)申請不到足夠的內(nèi)存就拋OutOfMemoryError異常罢低。
7、直接內(nèi)存并不是運(yùn)行時(shí)數(shù)據(jù)區(qū)的一部分,也不是虛擬機(jī)管理的內(nèi)存區(qū)域网持。本地內(nèi)存不足也會導(dǎo)致OutOfMemoryError異常宜岛。但是linux系統(tǒng)也可能觸發(fā)OOM機(jī)制kill掉內(nèi)存占用最大的一個進(jìn)程。
二功舀、對象的內(nèi)存布局可以分為三塊區(qū)域:1萍倡、對象頭(Header);2辟汰、實(shí)例數(shù)據(jù)(Instance Data)列敲;3、對齊填充(Padding)帖汞。
1戴而、對象頭包括兩部分,第一部分用于儲存對象自身的運(yùn)行時(shí)數(shù)據(jù)如哈希碼(HashCode)翩蘸、GC分代年齡所意、鎖狀態(tài)標(biāo)志、線程持有的鎖催首、偏向線程ID扁眯、偏向時(shí)間戳等。另一部分是類型指針翅帜,即對象指向它的類元數(shù)據(jù)的指針姻檀,虛擬機(jī)通過這個指針來確定這個實(shí)例是哪個對象的實(shí)例。
2涝滴、實(shí)例數(shù)據(jù)是對象真正儲存的數(shù)據(jù)绣版,默認(rèn)分配策略將相同長度的數(shù)據(jù)分配到一起;
3歼疮、對齊填充只是起到占位符的作用杂抽,不滿8位的補(bǔ)齊。
?
三韩脏、對象的訪問是通過棧上的reference數(shù)據(jù)來操作堆上的具體對象或者實(shí)例的缩麸,訪問方式分為兩種:1、句柄池赡矢;2杭朱、直接指針。
1吹散、句柄訪問方式弧械,java堆會劃分一塊區(qū)域作為句柄池,reference指向句柄池中的對象地址空民,句柄池中包含了對象實(shí)例數(shù)據(jù)與類型數(shù)據(jù)各自的地址刃唐。在對象被移動時(shí)reference指向的地址不需要改變。
2、直接訪問reference中儲存對象實(shí)例地址画饥。訪問速度稍快衔瓮,開銷小。HotSpot使用這種方式來訪問對象抖甘。