一、Java虛擬機包含如下幾個運行時數據區域:程序計數器、Java虛擬機棧、本地方法棧、Java堆、方法區。數組
二、程序計數器併發
1)在虛擬機的概念模型裏,字節碼解釋器工做時就是經過改變這個計數器的值來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等都須要依賴計數器來完成;佈局
2)爲了線程切換後能恢復到正確的執行位置,每條線程都須要有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲,所以是線程獨立的;spa
3)若是正在執行一個Java方法,這個計數器記錄的是正在執行的虛擬機字節碼指令的地址;若是正在執行的是Native方法,,這個計數器的值則爲空;線程
4)此內存區域是惟一一個在Java虛擬機規範中沒有規定任何OutOfMemoryError狀況的區域。指針
三、Java虛擬機棧對象
1)線程私有,生命週期與線程相同;生命週期
2)描述的是Java方法執行的內存模型:每一個方法執行時都會建立一個棧幀用於存儲局部變量表、操做數棧、動態連接、方法出口等信息,每一個方法從調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程;內存
3)兩種異常:StackOverflowError和OutOfMemoryError。編譯器
四、本地方法棧
1)與虛擬機棧做用類似,區別是虛擬機棧爲虛擬機執行Java方法服務,而本地方法棧爲虛擬機使用到的Native方法服務;
2)兩種異常:StackOverflowError和OutOfMemoryError。
五、Java堆
1)全部線程共享,存放對象實例和數組;
2)Java堆是垃圾收集器管理的主要區域;
3)Java堆能夠處於物理上不連續的內存空間中,只要邏輯上連續便可;
4)若是沒有內存完成實例分配,而且堆也沒法擴展時,將拋出OutOfMemoryError異常。
六、方法區
1)全部線程共享,存放被虛擬機加載的類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據;
2)JDK1.8仍然保留方法區的概念,只不過實現方式不一樣,取消永久代,方法存放於元空間(Metaspace),元空間仍然與堆不相連,但與堆共享物理內存,邏輯上可認爲在堆中;
3)沒法知足內存分配需求時,將拋出OutOfMemoryError異常。
七、使用new建立對象的過程
1)類加載檢查。首先檢查這個指令的參數是否能在常量池中定位到一個符號引用,並檢查這個符號引用表明的類是否已經被加載、解析和初始化,若是沒有,則必須執行類加載過程;
2)分配內存。兩種分配方式:指針碰撞和空閒列表。指針碰撞要求Java堆內存是絕對規整的,空閒列表容許Java堆不規整。採用那種方法取決於採用的垃圾收集器。
3)考慮併發問題。兩種方案:一種是CAS+失敗重試保證原子性,另外一種是本地線程分配緩衝(TLAB),事先給每一個線程分配一小塊內存,分配完了才須要同步鎖定。
4)初始化零值。保證對象的實例字段在Java代碼中不賦初值就能夠直接使用。
5)設置對象信息。例如對象是哪一個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡等信息。這些信息存放在對象頭中。
6)執行<init>方法。
八、對象的內存佈局
1)3塊區域:對象頭、實例數據、對齊填充;
2)對象頭:包含兩部分信息,一部分用於存儲自身的運行時數據,如哈希碼、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向鎖線程ID、偏向時間戳等,另外一部分是類型指針,指向它的類元數據的指針。
3)實例數據:是一個對象真正存儲的有效信息。
4)對齊填充:並非必然存在的,因爲HotpotVM的自動內存管理系統要求對象起始地址必須是8字節的整數倍,所以沒有對齊的部分須要經過填充來補全。
九、對象的訪問定位:主流的訪問方式有使用句柄和直接指針兩種,HotSpt採用的第二種方式訪問對象。