1 JVM的基本特性java
1.1 基於棧(Stack-based): 不一樣於Intel x86和ARM等比較流行的計算機處理器都是基於寄存器(register)架構,JVM是基於棧執行的。程序員
1.2 符號引用(Symbolic reference): 編譯後的.class文件中,除基本類型外的全部Java類型都是經過符號引用取得關聯的,而非顯式的基於內存地址的引用。算法
【符號引用以一組符號來描述所引用的目標,符號能夠是任何形式的字面量。例如,在Class文件中它以CONSTANT_Class_info、CONSTANT_Fieldref_info、CONSTANT_Methodref_info等類型的常量出現。編程
在編譯時,java類尚未被加載到內存中,因此並不知道所引用的類的實際地址,所以只能使用符號引用來代替;在解析階段,Java虛擬機會把類的二進制數據中的符號引用替換爲直接引用(指向內存地址)】緩存
1.3 垃圾回收機制: 類的實例經過用戶代碼進行顯式建立,但卻經過垃圾回收機制自動銷燬。性能優化
1.4 經過明確清晰基本類型確保平臺無關性: 像C/C++等傳統編程語言對於int類型數據在同平臺上會有不一樣的字節長度。JVM卻經過明確的定義基本類型的字節長度來維持代碼的平臺兼容性,從而作到平臺無關。網絡
1.5 網絡字節序(Network byte order): 是TCP/IP中規定好的一種數據表示格式。Java class文件的二進制表示使用的是網絡字節序,即基於big endian的字節序。架構
【字節序,即字節在電腦中存放時的序列與輸入(輸出)時的序列是先到的在前仍是後到的在前。 Little endian:將低序字節存儲在起始地址; Big endian:將高序字節存儲在起始地址】併發
2.Java字節碼在JVM中的運行app
2.1 編譯機制
Java字節碼沒法直接直接,須要JVM將其翻譯成機器碼。
在 HotSpot 裏面,翻譯過程有兩種形式:第一種是解釋執行,至關於同聲傳譯,即每解析一條字節碼,便翻譯成機器碼並執行;第二種是即時編譯(Just-In-Time compilation,JIT),則至關於線下翻譯,即將整個方法中所包含的字節碼統一翻譯成機器碼後在執行。前者的優點在於無需等待編譯,然後者的優點在於實際運行速度更快。
HotSpot 默認採用混合模式,綜合瞭解釋執行和即時編譯二者的優勢。它會先解釋執行字節碼,然後將其中反覆執行的熱點代碼,以方法爲單位進行即時編譯。
2.2 加載流程
執行 Java 代碼首先須要將它編譯而成的 class 文件加載到 Java 虛擬機的方法區中。實際運行時,執行引擎會執行方法區內的代碼。每當調用一個 Java 方法,Java 虛擬機會在當前線程的 Java 方法棧中生成一個棧幀,用以存放局部變量以及字節碼的操做數。這個棧幀的大小是提早計算好的,並且 Java 虛擬機不要求棧幀在內存空間裏連續分佈。當退出當前執行的方法時,不論是正常返回仍是異常返回,JVM均會彈出當前棧幀,並將之捨棄。
3.加載Java類
JVM加載 Java 類的過程可分爲三大步驟:加載、連接以及初始化。
3.1 加載
指經過類加載器查找字節流,建立類的過程。類加載器使用雙親委派模型,即接收到加載請求時,會先將請求轉發給父類加載器。
3.2 連接
指將建立成的類合併至 JVM中,使之可以執行的過程。
連接還分驗證(驗證被加載類是否知足 JVM約束)、準備(爲被加載類靜態字段分配內存)和解析(將被加載類中的符號引用解析成爲實際引用)三個階段。其中,JVM規範並不要求解析階段必定要在連接步驟中完成。
3.3 初始化
爲常量賦值,以及執行 <clinit> 方法的過程。類的初始化僅會被執行一次,這個特性被用來實現單例的延遲初始化。
4.垃圾回收
垃圾回收器採用可達性分析來探索全部存活的對象。它從一系列根對象出發,標記全部被引用的對象。爲了防止在標記過程當中堆棧的狀態發生改變,JVM採起STW(Stop-The-World) 操做,暫停其餘非垃圾回收線程。
一般來講,JVM採用分代回收的思想,將堆劃分爲新生代和老年代,而且在不一樣代中應用不一樣的垃圾回收算法。新生代再劃分爲 Eden 區和兩個大小一致的 Survivor 區。在Minor GC 中,Eden 區和非空 Survivor 區的存活對象會被複制到空的 Survivor 區中,當 Survivor 區中的存活對象複製次數超過必定數值時,它將被晉升至老年代。由於 Minor GC 只針對新生代進行垃圾回收,因此須要考慮從老年代到新生代的引用。爲了不掃描整個老年代,Java 虛擬機引入了名爲卡表的技術,標出老年代對新生代引用的內存區域。
G1 垃圾回收器包含三個階段(新生代GC、併發標記週期、混合GC);G1將堆劃分爲多個等大的區域,優先收集垃圾最多的區域,從而最大化垃圾回收的效益。
Java 11 中引入的實驗性垃圾回收器 ZGC,僅在掃描可達對象時請求 Stop-The-World,暫停應用線程。所以,它宣稱可將 GC 暫停時間控制在 10ms 如下。ZGC 暫時沒有應用分代回收的思路,將整個堆空間當作一塊,其代價是垃圾回收 CPU 消耗較高。
5.Java內存模式
在現代計算機系統中,代碼一般不會按照書寫順序執行。形成這一狀況的緣由有三個,分別爲編譯器的重排序,處理器的亂序執行,以及內存系統的重排序。
之內存系統重排序爲例,在多處理器體系架構下,每一個處理器均可能緩存了一部分數據。因爲時刻保持緩存數據與內存數據同步的性能代價太大,所以部分體系架構可能容許緩存數據與內存數據不一樣步。這對 Java 程序的影響即是,兩個不一樣的 Java 線程在同一時間內看到的同一塊內存地址中的值可能不一樣。
Java 內存模型是針對上述問題而提出的一套規範,用以容許 Java 程序員更爲細緻地定義 Java 程序的內存行爲。它經過定義了一系列的 happens-before 操做,讓應用程序開發者可以輕易地表達不一樣線程的操做之間的內存可見性。
在遵照 Java 內存模型的前提下,即時編譯器以及底層體系架構可以調整內存訪問操做,以達到性能優化的效果。若是開發者沒有正確地利用 happens-before 規則,那麼將可能致使數據競爭。
Java 內存模型是經過內存屏障來禁止重排序的。對於即時編譯器來講,內存屏障將限制它所能作的重排序優化。對於處理器來講,內存屏障會致使緩存的刷新操做。
6. 參考文獻
6.1 狼小戰的博客《Java虛擬機必學之四大知識要點》
6.2 hello_史努比《java -- JVM的符號引用和直接引用》
6.3 百度百科《字節序》