1. 程式人生 > 程式設計 >Java程式執行原理分析

Java程式執行原理分析

class檔案內容

  • class檔案包含Java程式執行的位元組碼
  • 資料嚴格按照格式緊湊排列在class檔案的二進位制流,中間無分割符
  • 檔案開頭有一個0xcafebabe(16進位制)特殊的標誌

在這裡插入圖片描述

JVM執行時資料區

在這裡插入圖片描述

執行緒獨佔: 每個執行緒都會有它獨立的空間,隨執行緒的生命周而建立和銷燬 執行緒共享: 所有執行緒都能訪問這塊記憶體資料,隨虛擬機器器或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"

複製程式碼

程式完整執行分析

在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

在這裡插入圖片描述