一,JVM內(nèi)存結構
jvm03.png
- JVM內(nèi)存主要分為:堆內(nèi)存、方法區(qū)和棧
- 堆內(nèi)存存儲對象實例净嘀,由新生代和老年代組成
- 方法區(qū)存儲類信息报咳、常量、靜態(tài)變量等數(shù)據(jù)
- 棧又分為java虛擬機棧和本地方法棧挖藏,主要用于方法的執(zhí)行
二暑刃,各區(qū)域參數(shù)設置
jvm04.png
- -Xms 堆的最小空間大小。
- -Xmx 堆的最大空間大小膜眠。
- -XX:NewSize 新生代最小空間大小岩臣。
- -XX:MaxNewSize 新生代最大空間大小。
- -XX:PermSize 永久代(方法區(qū))最小空間大小宵膨。
- -XX:MaxPermSize 永久代(方法區(qū))最大空間大小架谎。
- -Xss 每個線程的堆棧大小。
老年代空間=堆空間-年輕代大空間
jvm05.png
三辟躏,Java堆(Heap)
- 存放對象實例狐树。
- 所有線程共享。
- 垃圾收集的主要區(qū)域鸿脓,采用分代收集算法抑钟,分為新生代和老年代,新生代內(nèi)存又分為Eden空間野哭、From Survivor空間在塔、To Survivor空間,默認按8:1:1的比例分配。
- 物理不連續(xù)拨黔,邏輯上連續(xù)蛔溃,可擴展(通過-Xmx和-Xms控制)。
- 堆內(nèi)存不足以完成實例分配篱蝇,并且無法再擴展時贺待,拋出OutOfMemoryError。
四零截,方法區(qū)(Method Area)
- 存儲已加載的類信息麸塞、常量、靜態(tài)變量涧衙、即時編譯器編譯后的代碼哪工,又稱為永久代(Permanent Generation)。
- 所有線程共享弧哎。
- 方法區(qū)主要針對常量池的回收和對類型的卸載雁比,回收“成績”較差,其中類型的卸載條件相當苛刻撤嫩。
- 當方法區(qū)無法滿足內(nèi)存分配需求時偎捎,將拋出OutOfMemoryError。
五,Java虛擬機棧(JVM Stacks)
- 線程私有的茴她,它的生命周期與線程相同
- 每個方法被調(diào)用直至執(zhí)行完成的過程蜕径,對應一個棧幀在虛擬機棧中從入棧到出棧的過程。
- 虛擬機棧是執(zhí)行Java方法的內(nèi)存模型:每個方法被執(zhí)行時會創(chuàng)建一個棧幀(Stack Frame)败京,用于存儲局部變量表、操作棧梦染、動態(tài)鏈接赡麦、方法出口等信息。
- 局部變量表存放了編譯期可知的基本類型(boolean帕识、byte泛粹、char、short肮疗、int晶姊、float、long伪货、double)们衙、對象引用(reference類型)和returnAddress類型(指向了一條字節(jié)碼指令的地址)。64位長度的long和double類型會占用2個局部變量空間(Slot)碱呼,其余類型只占用1個
- 局部變量表所需的內(nèi)存空間在編譯期間完成分配蒙挑,方法運行期間不會改變局部變量表的大小。
- 動態(tài)連接:每個棧幀都包含一個指向運行時常量池(方法區(qū)的一部分)中該棧幀所屬方法的引用愚臀。持有這個引用是為了支持方法調(diào)用過程中的動態(tài)連接忆蚀。Class文件的常量池中有大量的符號引用,字節(jié)碼中的方法調(diào)用指令就以常量池中指向方法的符號引用為參數(shù)姑裂。這些符號引用一部分會在類加載階段或第一次使用的時候轉(zhuǎn)化為直接引用馋袜,這種轉(zhuǎn)化稱為靜態(tài)解析。另一部分將在每一次的運行期間轉(zhuǎn)化為直接應用舶斧,這部分稱為動態(tài)連接欣鳖。
- 方法出口:返回方法被調(diào)用的位置,恢復上層方法的局部變量和操作數(shù)棧茴厉,如果無返回值观堂,則把它壓入調(diào)用者的操作數(shù)棧。
- 如果單個線程請求棧深度大于虛擬機所允許的深度(-Xss)呀忧,將拋出StackOverflowError
- 如果啟動一個新線程沒有足夠分配空間师痕,也無法擴展時,會拋出OutOfMemoryError
六而账,本地方法棧(Native Method Stacks)
- 虛擬機棧為執(zhí)行Java方法(也就是字節(jié)碼)服務胰坟,而本地方法棧為Native方法服務。
- 線程私有
- 與虛擬機棧一樣,本地方法棧區(qū)域也會拋出StackOverflowError和OutOfMemoryError
七笔横,程序計數(shù)器(Program Counter Register)
程序計數(shù)器是一塊較小的內(nèi)存空間竞滓,它的作用是當前線程所執(zhí)行的字節(jié)碼的行號指示器。
- 線程私有吹缔,各條線程之間的計數(shù)器互不影響商佑,獨立存儲。
- 在任何一個確定的時刻厢塘,一個處理器都只會執(zhí)行一條線程中的指令茶没。
- 如果正在執(zhí)行java方法,計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令地址晚碾。
- 如果是native方法抓半,則計數(shù)器值為空(native 方法 指得就是Java程序調(diào)用了非Java代碼,算是一種引入其它語言程序的接口)格嘁。
- 唯一在Java虛擬機規(guī)范中沒有OutOfMemoryError的區(qū)域笛求。
例子
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.log4j.Logger;
public class HelloWorld {
private static Logger LOGGER = Logger.getLogger(HelloWorld.class.getName());
public void sayHello(String message) {
SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.YYYY");
String today = formatter.format(new Date());
LOGGER.info(today + ": " + message);
}
}
這段程序的數(shù)據(jù)在內(nèi)存中的存放如下:
JUtH_20121024_RuntimeDataAreas_4_MemoryModel.png
八、對象的創(chuàng)建
- 虛擬機遇到new指令時
- 首先檢查這個指令的參數(shù)能否在常量池中定位到一個類的符號引用糕簿,并且檢查引用代表的類是否已被加載探入、解析和初始化過。如果沒有懂诗,則執(zhí)行類加載過程(第7章 虛擬機類加載機制)新症。
- 加載檢查通過后,分配內(nèi)存(內(nèi)存在類加載完成后便可完全確定)响禽。
- 內(nèi)存分配完成后徒爹,虛擬機對對象進行必要的設置,如對象是哪個類的實例芋类、如何找到類的元數(shù)據(jù)信息等(都放在對象的對象頭中)隆嗅。
- 從虛擬機角度看,一個新的對象產(chǎn)生了侯繁,但從java程序視角看胖喳,對象創(chuàng)建才剛剛開始,因為<init>方法還沒有執(zhí)行贮竟,所有字段為零丽焊。執(zhí)行new指令之后會接著執(zhí)行<init>方法(構造方法),進行初始化咕别,這樣一個真正可用的對象才算完成產(chǎn)生技健。
九、對象的內(nèi)存布局
對象在內(nèi)存中存儲的布局可以分為3塊區(qū)域:對象頭惰拱、實例數(shù)據(jù)雌贱、對齊填充
- 對象頭(Header)包含兩部分
- 對象的運行時數(shù)據(jù),如哈希碼、GC分代年齡等欣孤。長度在32位和64位的虛擬機中馋没,分別為32bit、 64bit,官方稱它為Mark Word降传。
對象mark word.PNG - 類型指針篷朵,對象指向它的類元數(shù)據(jù)的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例婆排。
- 注:如果對象是一個java數(shù)組声旺,對象頭中還必須有一塊記錄數(shù)據(jù)長度的數(shù)據(jù)
-
實例數(shù)據(jù)(InstanceData)
對象真正存儲的有用信息,各種類型的字段內(nèi)容泽论,包括父類繼承的和子類定義的字段 -
對齊填充(Padding)
由于HotSpot虛擬機要求對象的起始地址必須是8字節(jié)的整數(shù)倍,就是對象大小必須是8字節(jié)的整數(shù)倍卡乾。對象頭正好是8字節(jié)的倍數(shù)翼悴。當實例數(shù)據(jù)部分沒有對齊時,需要通過對齊填充來補全幔妨。
十鹦赎、對象的訪問定位
- Java程序通過棧上的reference數(shù)據(jù)來操作堆上的具體對象。
- 目前主流的對象訪問方式有兩種:使用句柄和直接指針误堡。
-
使用句柄 是間接訪問古话,優(yōu)點是reference中存儲的是穩(wěn)定的句柄地址,對象移動時只會改變句柄中的實例數(shù)據(jù)指針锁施。
句柄訪問.PNG -
使用直接指針 是直接訪問陪踩,優(yōu)點就是速度快。
指針直接訪問.PNG
參考資料
https://segmentfault.com/a/1190000010412582
http://www.ityouknow.com/jvm/2017/08/25/jvm-memory-structure.html
http://www.reibang.com/p/3fecd4286f78