Java程序運行原理分析


class文件內容

  • class文件包含Java程序執行的字節碼
  • 數據嚴格按照格式緊湊排列在class文件的二進制流,中間無分割符
  • 文件開頭有一個0xcafebabe(16進制)特殊的標志

img

JVM運行時數據區

img

線程獨占: 每個線程都會有它獨立的空間,隨線程的生命周而創建和銷毀

線程共享: 所有線程都能訪問這塊內存數據,隨虛擬機或GC而創建和銷毀

方法區

  • 方法區是各個線程共享的內存區域
  • 用於存儲已被虛擬機加載的類信息, 常量,靜態變量, 即時編譯后的代碼等數據
  • 雖然Java虛擬機規范把方法區描述為堆的一個邏輯部分, 但它卻有一個別名叫Non-Heap, 目的應該是與Java堆區分開來
  • Oracle的Hotspot虛擬機在Java7中方法區放在’永久代’(Permanent Generation), Java8放在元數據空間, 並且通過GC機制對這個區域進行管理
  • 運行時常量池是方法區的一部分

Java堆

  • Java堆是被所有共享的一塊內存區域, 在虛擬機啟動時創建
  • 存放對象的實例
  • 垃圾收集器的主要管理區域
  • Java堆還可以細分為: 新生代和老年代, 新生代又可以細分為Eden 空間, From Survivor空間 和To Survivor空間
  • 空間滿了會拋OutOfMemoryError

Java虛擬機棧

  • Java虛擬機棧是線程私有的, 它的生命周期與線程相同
  • Java虛擬機棧描述的是Java方法執行的內存模型: 每個方法被執行的的時候都會同時創建一個棧幀(棧幀是方法運行時的基礎數據結構)用於存儲局部變量表, 操作棧, 動態鏈接, 方法出口等信息.
  • 棧內存默認最大是1M, 超出則拋出StackOverFlowError

本地方法棧

  • 本地方法棧與虛擬機棧的功能類似, 虛擬機棧是為虛擬機執行Java方法而准備的, 本地方法棧是為虛擬機使用Native本地方法而准備的
  • Hotspot虛擬機中虛擬機棧與本地方法棧的實現方式一樣, 超出大小后也會拋StackOverFlowError

程序計數器

  • 程序計數器是線程私有的一塊較小的內存空間
  • 記錄當前線程執行的字節碼位置, 存儲的是字節碼指令地址, 如果執行Native方法, 則計數器為空
  • CPU同一時間, 只會執行一條線程的指令. JVM多線程會輪流切換並分配CPU的執行時間的方式. 為了線程切換后, 需要通過程序計數器來恢復正確的執行位置

查看class文件內容

使用Demo.Java進行測試, 運行javac Demo.java編譯成class文件, 然后運行javap -v Demo.class > Demo.txt查看class文件內容

Demo.Java

public class Demo{
    public static void main(String[] args){
        int x = 500;
        int y = 100;
        int a = x / y;
        int b = 50;
        System.out.println(a + b);
    }
}

Demo.txt

Classfile /E:/*/Demo.class
  Last modified 2019-6-30; size 412 bytes
  MD5 checksum efd785af33e58aa9fc9834110b74b87b
  Compiled from "Demo.java"
public class Demo
  minor version: 0      //次版本號
  major version: 52       //主版本號 版本號規則: JDK5,6,7,8分別對應49,50,51,52
  flags: ACC_PUBLIC, ACC_SUPER    //訪問標志
Constant pool:    // 常量池 類信息包含的靜態常量, 編譯之后就能確認
   #1 = Methodref          #5.#14         // java/lang/Object."<init>":()V
   #2 = Fieldref           #15.#16        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = Methodref          #17.#18        // java/io/PrintStream.println:(I)V
   #4 = Class              #19            // Demo
   #5 = Class              #20            // java/lang/Object
   #6 = Utf8               <init>
   #7 = Utf8               ()V
   #8 = Utf8               Code
   #9 = Utf8               LineNumberTable
  #10 = Utf8               main
  #11 = Utf8               ([Ljava/lang/String;)V
  #12 = Utf8               SourceFile
  #13 = Utf8               Demo.java
  #14 = NameAndType        #6:#7          // "<init>":()V
  #15 = Class              #21            // java/lang/System
  #16 = NameAndType        #22:#23        // out:Ljava/io/PrintStream;
  #17 = Class              #24            // java/io/PrintStream
  #18 = NameAndType        #25:#26        // println:(I)V
  #19 = Utf8               Demo
  #20 = Utf8               java/lang/Object
  #21 = Utf8               java/lang/System
  #22 = Utf8               out
  #23 = Utf8               Ljava/io/PrintStream;
  #24 = Utf8               java/io/PrintStream
  #25 = Utf8               println
  #26 = Utf8               (I)V
{
  public Demo();     // 默認隱式無參的構造函數
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main(java.lang.String[]);    //程序的入口main方法
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC     //訪問控制
    Code:
      stack=3, locals=5, args_size=1      //方法棧棧幀中操作數棧的深度,本地變量數量,參數數量
         0: sipush        500     //Jvm執行引擎執行這些源碼編譯過后的指令碼, javap翻譯出來的
         3: istore_1            //是操作符, class 文件內存儲的是指令碼, 前面的數據是偏移量,
         4: bipush        100     //Jvm根據這個去區分不同的指令. 詳情參照'JVM指令碼表'
         6: istore_2
         7: iload_1
         8: iload_2
         9: idiv
        10: istore_3
        11: bipush        50
        13: istore        4
        15: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        18: iload_3
        19: iload         4
        21: iadd
        22: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        25: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 7
        line 6: 11
        line 7: 15
        line 8: 25
}
SourceFile: "Demo.java"

程序完整運行分析

img
img


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM