JVM 学习笔记 1. JVM 运行模型
目錄
1. JVM 啟動流程
如下圖所示:
2. JVM 基本結構
兩幅經典的模型圖:
其中:
棧的執行過程
JVM 沒有寄存器(除PC),所有的參數傳遞都使用操作數棧。
public static int add(int a,int b){int c = 0;c = a + b;return c; }編譯之后,注意操作數棧如何實現參數傳遞。
0: iconst_0 // 0壓棧1: istore_2 // 彈出int,存放于局部變量22: iload_0 // 把局部變量0壓棧3: iload_1 // 局部變量1壓棧4: iadd // 彈出2個變量,求和,結果壓棧5: istore_2 // 彈出結果,放于局部變量26: iload_2 // 局部變量2壓棧7: ireturn // 返回局部變量表和操作數棧的變化過程:
棧上分配
public class OnStackTest {public static void alloc() {byte[] b = new byte[2];b[0] = 1;}public static void main(String[] args) {long b = System.currentTimeMillis();for (int i = 0; i < 100000000; i++) {alloc();}long e = System.currentTimeMillis();System.out.println(e - b);} }默認運行,采用了棧上分配了. 測試結果:
? jvm-learning java com.nil2inf.memory.OnStackTest 52 ? jvm-learning java -server -Xmx10m -Xms10m -XX:+DoEscapeAnalysis -XX:+PrintGC com.nil2inf.memory.OnStackTest 40 ? jvm-learning java -server -Xmx10m -Xms10m -XX:-DoEscapeAnalysis -XX:+PrintGC com.nil2inf.memory.OnStackTest [GC 2624K->432K(9856K), 0.0014784 secs] [GC 3056K->416K(9856K), 0.0006314 secs] [GC 3040K->432K(9856K), 0.0004287 secs] [GC 3056K->416K(9728K), 0.0003950 secs] ... ... [GC 3280K->400K(9984K), 0.0001506 secs] [GC 3280K->400K(10048K), 0.0001993 secs] [GC 3408K->400K(10048K), 0.0001092 secs] ... ... [GC 3664K->400K(10176K), 0.0001128 secs] 582棧上分配:
- 棧上分配、標量替換技術是JVM的一項優化技術,涉及到逃逸分析和標量替換。
- 通常只有沒有逃逸的小對象,才可以棧上分配。反之,大對象或者逃逸對象無法棧上分配。
- 棧上分配的目的是減清 GC 的壓力。
3. 內存模型
read and load 從主存復制變量到當前工作內存
use and assign 執行代碼,改變共享變量值
store and write 用工作內存數據刷新主存相關內容
可見性
一個線程修改了變量,其他線程可以立即知道。
如何確保可見性:
- volatile
- synchronized (unlock之前,寫變量值回主存)
- final(一旦初始化完成,其他線程就可見)
有序性
在本線程內,操作都是有序的。在線程外觀察,操作都是無序的。(指令重排 或 主內存同步延時)。
重排序
指令重排序。
4. 虛擬機的運行方式
虛擬機中存在兩種運行方式:分為解釋和編譯。
字節碼指令編譯為本機機器指令過程,有解釋器或者編譯器完成.
a. 解釋
解釋是最簡單的字節碼編譯形式. 解釋器查找每條字節碼指令對應的硬件編碼,再由 CPU 執行相應的硬件指令。
這個過程可以準確執行字節碼,沒有機會對某個指令集合進行優化,難以發揮目標平臺處理器的最佳性能。
b. 編譯
編譯執行應用程序時,編譯器會將加載運行時會用到的全部代碼. 因為編譯器可以將字節碼編譯為本地代碼,因此它可以獲取到完整或部分運行時上下文信息,并依據收集到的信息決定到底應該如何編譯字節碼。
可以對指令集合進行優化,優化后的指令集合會被存儲到 code cache 的數據結構中,當下次執行這部分字節碼序列時,會執行這些經過優化后被存儲到code cache的指令集合。在某些情況下,性能計數器會失效,并覆蓋掉先前所做的優化,這時,編譯器會執行一次新的優化過程。
使用code cache的好處是優化后的指令集可以立即執行.
c. 優化
隨著動態編譯器一起出現的是性能計數器。
例如,編譯器會插入性能計數器,以統計每個字節碼塊(對應與某個被調用的方法)的調用次數。 -- 代碼的熱度.
運行時數據監控有助于編譯器完成多種代碼優化工作,進一步提升代碼執行性能。
轉載于:https://www.cnblogs.com/nil2inf/p/4722276.html
總結
以上是生活随笔為你收集整理的JVM 学习笔记 1. JVM 运行模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [转]VMware虚拟机上网络连接(ne
- 下一篇: 数据库操作,复制表