日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM 学习笔记 1. JVM 运行模型

發布時間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM 学习笔记 1. JVM 运行模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄

  • JVM 啟動流程
  • JVM 基本結構
  • 內存模型
  • 虛擬機的運行方式
  • 1. JVM 啟動流程

    如下圖所示:

    2. JVM 基本結構

    兩幅經典的模型圖:

    其中:

  • PC寄存器:每個線程都擁有一個PC寄存器,用于指向下一條指令的地址,因此,PC是線程私有的內存。當執行 native 方法時,PC的值為undefined。此內存區域是唯一一個在 Java 虛擬機規范中沒有規定 OOM 的區域。
  • Java 棧:是線程私有的,棧是由一系列幀(frame)組成。JVM 是 Stack-Based 的,棧幀中保存:方法的返回值(Return Value),局部變量表(Local variables),操作數棧(Operand Stack)和常量池指針(Constant Pool Refernce)。其中,局部變量表包含了參數和局部變量(槽)。兩個經典的異常:StackOverflowError 和 OutOfMemoryError。
  • 本地方法棧:JVM 執行 Native 方法所使用的棧,HotSpot 直接將 Java 棧和 Native 棧合二為一。
  • Java 堆:用于保存應用程序對象實例,被所有線程所共享,是發生 GC 的主要區域。對于分代 GC 而言,堆也是分代的:新生代和老年代。Java 堆可能劃分出多個線程私有的分配緩存區(TLAB, Thread Local Allocation Buffer)。
  • 方法區:被各個線程共享。用來存儲已被虛擬機加載的類信息、常量、靜態變量、方法的字節碼等數據。別名是 Non-Heap,在 HotSpot 中,方法區經常被稱為永久代(PermG),因為HotSpot將分代延生到方法區,該區域也可盡心回收。值得注意的是,JDK1.7的HotSpot已經將Interned Strings(字符串常量池)移出永久代。
  • 運行時常量池(Runtime Constant Pool):方法區的一部分。主要用來存放編譯期生成的各種字面量和符號引用,當然,運行時也可以將新的常量放入池中,如:String.intern()方法。
  • 直接內存(Direct Memory):不是 JVM 運行時數據區的一部分,沒有在虛擬機規范中定義該內存區域。NIO 利用 Native 函數庫直接分配堆外內存,避免了Java堆和 堆外內存的來回復制,提高了性能。
  • 棧的執行過程

    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 關鍵字能夠保證變量更改在其他線程立即可見。
  • 可見性

    一個線程修改了變量,其他線程可以立即知道。

    如何確保可見性:

    • 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 运行模型的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。