您現在的位置是:首頁 > 舞蹈首頁舞蹈

「JVM系列」 從一到掌握JVM系列之Java虛擬機器棧

由 Java如何學 發表于 舞蹈2021-09-10
簡介每個棧幀中包括區域性變量表(Local Variables)、運算元棧(Operand Stack)、指向執行時常量池的引用(A reference to the run-time constant pool)、方法返回地址(Return

棧的特點是什麼

前言

本文主要介紹如何結合位元組碼指令理解Java虛擬機器棧和棧幀,並進行深入分析以及對記憶體模型的介紹和驗證。

虛擬機器棧概述

由於跨平臺性的設計,Java的指令都是根據棧來設計的。不同平臺 CPU 架構不同,所以不能設計為基於暫存器的。 優點是跨平臺,指令集小,編譯器容易實現,缺點是效能下降,實現同樣的功能需要更多的指令。 有不少 Java 開發人員一提到Java記憶體結構,就會非常粗粒度地將JVM中的記憶體區理解為僅有 Java 堆(heap)和 Java 棧(stack)?為什麼? 首先棧是執行時的單位,而堆是儲存的單位

棧解決程式的執行問題,即程式如何執行,或者說如何處理資料。

堆解決的是資料儲存的問題,即資料怎麼放,放哪裡。

Java虛擬機器棧是什麼

Java虛擬機器棧(Java Virtual Machine Stack),早期也叫 Java 棧。每個執行緒在建立時都會建立一個虛擬機器棧,其內部儲存一個個的棧幀(Stack Frame),對應著一次次的 Java 方法呼叫。

是執行緒私有的

生命週期

生命週期和執行緒一致,也就是執行緒結束了,該虛擬機器棧也銷燬了

作用

主管Java程式的執行,它儲存方法的區域性變數、部分結果,並參與方法的呼叫和返回。

區域性變數,它是相比於成員變數來說的(或屬性)

基本資料型別變數 VS 引用型別變數(類、陣列、介面)

棧的特點

棧是一種快速有效的分配儲存方式,訪問速度僅次於程式計數器。

JVM 直接對 Java 棧的操作只有兩個:每個方法執行,伴隨著進棧(入棧、壓棧)執行結束後的出棧工作

對於棧來說不存在垃圾回收問題(棧存在溢位的情況)GC;OOM

結合位元組碼指令理解Java虛擬機器棧和棧幀

棧幀

每個棧幀對應一個被呼叫的方法,可以理解為一個方法的執行空間。

每個棧幀中包括區域性變量表(Local Variables)、運算元棧(Operand Stack)、指向執行時常量池的引用(A reference to the run-time constant pool)、方法返回地址(Return Address)和附加資訊。

【領取資料】

區域性變量表

方法中定義的區域性變數以及方法的引數存放在這張表中,區域性變量表中的變數不可直接使用,如需要使用的話,必須透過相關指令將其載入至運算元棧中作為運算元使用。

運算元棧

以壓棧和出棧的方式儲存運算元的。

動態連結

每個棧幀都包含一個指向執行時常量池中該棧幀所屬方法的引用,持有這個引用是為了支援方法呼叫過程中的動態連線(Dynamic Linking)。

方法返回地址:當一個方法開始執行後,只有兩種方式可以退出,一種是遇到方法返回的位元組碼指令;一種是遇見異常,並且這個異常沒有在方法體內得到處理。

「JVM系列」 從一到掌握JVM系列之Java虛擬機器棧

程式碼展示

class Person{ private String name=“Jack”; private int age; private final double salary=100; private static String address; private final static String hobby=“Programming”; public void say(){ System。out。println(“person say。。。”); } public static int calc(int op1,int op2){ op1=3; int result=op1+op2; return result; } public static void order(){ } public static void main(String[] args){ calc(1,2); order(); } }

Compiled from “Person。java” class Person { 。。。 public static int calc(int, int); Code: 0: iconst_3 //將int型別常量3壓入[運算元棧] 1: istore_0 //將int型別值存入[區域性變數0] 2: iload_0 //從[區域性變數0]中裝載int型別值入棧 3: iload_1 //從[區域性變數1]中裝載int型別值入棧 4: iadd //將棧頂元素彈出棧,執行int型別的加法,結果入棧 【For example, the iadd instruction (§iadd) adds two int values together。 It requires that the int values to be added be the top two values of the operand stack, pushed there by previous instructions。 Both of the int values are popped from the operand stack。 They are added, and their sum is pushed back onto the operand stack。 Subcomputations may be nested on the operand stack, resulting in values that can be used by the encompassing computation。】 5: istore_2 //將棧頂int型別值儲存到[區域性變數2]中 6: iload_2 //從[區域性變數2]中裝載int型別值入棧 7: ireturn //從方法中返回int型別的資料 。。。 }

深入分析

棧指向堆

如果在棧幀中有一個變數,型別為引用型別,比如 Object obj=new Object(),這時候就是典型的棧中元素指向堆中的物件。

「JVM系列」 從一到掌握JVM系列之Java虛擬機器棧

方法區指向堆

方法區中會存放靜態變數,常量等資料。如果是下面這種情況,就是典型的方法區中元素指向堆中的物件。

private static Object obj=new Object();

「JVM系列」 從一到掌握JVM系列之Java虛擬機器棧

堆指向方法區

方法區中會包含類的資訊,堆中會有物件,那怎麼知道物件是哪個類建立的呢?

「JVM系列」 從一到掌握JVM系列之Java虛擬機器棧

總結

最後,感謝大家的觀看,謝謝大家的支援,最好是一鍵三連!

「JVM系列」 從一到掌握JVM系列之Java虛擬機器棧