1. Java虛擬機的架構java
1.0 運行時數據區:通過編譯的class文件,由ClassLoader(類加載子系統)加載後會交給執行引擎執行。在執行引擎執行過程當中,會產生一些數據,這些數據被稱爲運行時數據,存儲這些數據的內存區域稱爲運行時數據區。性能優化
1.1 Java的NIO庫容許Java程序使用直接內存,訪問直接內存的速度優於Java堆。出於性能的考慮,讀寫頻繁的場合會考慮使用直接內存。架構
1.2 本地方法棧和Java棧很是相似,最大的不一樣在於Java棧用於Java方法的調用,而本地方法棧用於本地方法的調用。jvm
1.3 PC 寄存器: Program Counter寄存器,即:程序計數器,跟隨線程的啓動而建立。用於記錄當前線程重在執行的字節碼指令位置。【線程專有】函數
1.4 在任意時刻,一個Java線程老是在執行一個方法。若是這個方法不是本地方法,PC寄存器就會指向當前正在被執行的指令;若是這個方法是本地方法,PC寄存器的值是undefined。性能
1.5 JVM內存結構的五大區域:Java棧(虛擬機棧)、本地方法棧、PC寄存器、方法區、Java堆。其中,Java棧、本地方法棧、PC寄存器是線程專有的。優化
2.Java堆spa
2.1 結構:根據垃圾回收機制的不一樣,Java堆可能有不一樣的結構。最多見的一種結構是將Java堆分爲新生代和老年代。線程
2.2 流程:3d
在絕大多數狀況下,對象首先會分配到eden區,在一次新生代回收後,若是對象還存活,會進入s0或則s1區;以後,每經歷一次新生代回收,若是對象還存活,則年齡加1。年齡達到必定條件後,會被認爲是老年對象,進入老年代。
3.Java棧(虛擬機棧)
虛擬機棧是Java方法執行的內存結構,虛擬機會在每一個方法執行時建立一個「棧幀」,用於存儲局部變量表,操做數棧等信息。當方法執行完畢後,該棧幀會從虛擬機棧中出棧。
3.1棧幀出入棧【函數調用】過程
3.1.1 出棧順序:先入後出
3.1.2 每次函數調用的數據都是經過Java棧傳遞的。
3.1.3 Java棧中保存的主要內容是是棧幀。[棧幀中保存着當前函數的局部變量、操做數、中間運算結果等數據]。
3.2 Java棧基本構架
3.2.1 棧幀至少包含局部變量表、操做數棧和幀數據區。
3.4 當棧空間不足時,函數調用沒法繼續,系統會拋出StackOverflowError棧溢出錯誤。【能夠經過-Xss設置線程的最大棧空間】
3.5 StackOverflowError演示【遞歸死循環】
package com.blueStarWei.jvm; public class StackOverflowError { private static int count = 0; public static void main(String[] args) { try{ recursion(); }catch(Throwable e){ System.out.println("deep of calling : "+count); e.printStackTrace(); } } public static void recursion(){ count++; recursion(); } }
3.5.1 日誌輸出
//根據-Xss配置的參數不一樣,被調用的次數會不一樣 deep of calling : 31661 java.lang.StackOverflowError at com.blueStarWei.jvm.StackOverflowError.recursion(StackOverflowError.java:18)
4.方法區
4.1 在JDK1.六、1.7中,方法區能夠理解爲永久區(Permanent).。JDK1.8中,永久區被完全移除,取而代之的是元數據區(堆外的直接內存)
4.2 方法區是被全部線程共用的內存空間,在JVM啓動時建立.
4.3 運行時常量池 : 除了每一個類或接口中定義的常量,它還包含了全部對方法和字段的引用。所以當須要一個方法或字段時,JVM經過運行時常量池中的信息從內存空間中來查找其相應的實際地址。
4.4 設置參數
參數 | 做用 | 備註 |
-XX:PremSize | 設置永久區初始化空間 | |
-XX: MaxPremSize | 設置永久區的最大空間 | 默認64MB |
-XX:MaxMetaspaceSize | 設置元數據區的最大空間 | 若是不指定大小,虛擬機會耗盡全部可用的系統內存 |
4.5 垃圾收集在這個區域是比較少出現的,這區域的內存回收目標重要是針對常量池的回收和類型的卸載。
5. 局部變量表
5.1 槽位複用
5.1.1 含義:若是局部變量A超出其做用域,那麼在其做用域以後的局部變量B會複用A的槽位。
5.1.2 優勢: 節省資源
5.1.3 注意:若是A做用域以後沒有新的變量,A不會從局部變量表中移除【可使用-XX:+PrintGC查看GC信息,判斷是否觸發GC】
//局部變量a仍然存在於局部變量表中,不會觸發GC public void localGC1(){ { byte[] a = new byte[6*1024*1024]; } System.gc(); } //局部變量a的槽位已經被局部變量b複用,觸發GC[回收局部變量a] public void localGC2(){ { byte[] a = new byte[6*1024*1024]; } int b = 0; System.gc(); }
6.參考文獻
6.1 《實戰Java虛擬機 - JVM故障診斷與性能優化》