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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

JVM_03 运行时数据区 [ 虚拟机栈 ]

發布時間:2025/3/15 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM_03 运行时数据区 [ 虚拟机栈 ] 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、前言

(棧并不是越大越好,越多可以防止出現StackOverflowError晚點出現,但是棧越大,也就代表著虛擬機棧是一定的,你的棧越大,別的棧就會小)

二、 什么是 Java virtual machine?

  • 棧的概述
    每創建一個線程就會創建一個Java棧,每一個Java棧中都會有很多棧幀(局部變量表 | 操作數棧 | 動態鏈接 | 方法返回地址 | 一些附加信息) 掌握
    解釋:
    • (1). 虛擬機棧(Java Virtual Machine Stacks)和線程是緊密聯系的,每創建一個線程時就會對應創建一個Java棧,所以Java棧也是"線程私有"的內存區域,這個棧中又會對應包含多個棧幀,每調用一個方法時就會往棧中創建并壓入一個棧幀,棧幀是用來存儲方法數據和部分過程結果的數據結構,每一個方法從調用到最終返回結果的過程,就對應一個棧幀從入棧到出棧的過程
      [先進后出]
    • (2). 棧幀中有如下部分組成:
    • (3). 棧的其他介紹
  • 存放于棧中的東西如下 [掌握]
  • (8種基本類型的變量+對象的引用變量+實例方法都是在函數的棧內存中分配[局部變量])

  • 棧內存溢出(StackOverflowError) -Xss參數
    • 棧幀過多導致棧內存溢出(方法的遞歸調用,沒設置正確停止條件)
    • 棧幀過大(棧幀大小>棧內存)
    Exception in thread "main" java.lang.StackOverflowError //sayHello()發生了遞歸 public class DemoT {public static void main(String[] args) {sayHello();}public static void sayHello(){sayHello();} }

    二、 局部變量表(LocalVariables) 掌握

  • 定義為一個數字數組,主要用于存儲方法參數和定義在方法體內的局部變量(這些數據類型包括各種基本數據類型、對象引用(reference)以及return Address類型)

  • 由于局部變量是建立在線程的棧上,是線程私有數據,因此不存在數據安全問題

  • 局部變量表所需容量大小是在編譯期確定下來的。(并保存在方法Code屬性的maximum local variables數據項中,在方法運行期間不會改變局部變量表的大小的)

  • //使用javap -v 類.class 或者使用jclasslib public class LocalVariableTest {public static void main(String[] args) {LocalVariableTest test=new LocalVariableTest();int num=10;test.test1();}public static void test1(){Date date=new Date();String name="xiaozhi";} }

    jclasslib說明:


  • 關于slot的理解(引用數據類型(方法的返回地址)占用1個slot)
    • 局部變量表,是基本的存儲單元是slot(變量槽)
    • 在局部變量表中,32位以內的類型只占有一個slot(包括引用數據類型),64位的類型(long和double)占有兩個slotbyte、short、char在存儲前被轉換為int,boolean也被轉換為int(0表示fasle,非0表示true) long和double則占據兩個slot
  • Jvm會為局部變量表中的每一個slot都分配一個訪問索引,通過這個索引即可成功訪問到局部變量表中指定的局部變量值

  • 如果需要訪問局部變量表中一個64bit的局部變量值時,只需要使用前一個索引即可(比如:訪問long或double類型變量)

  • 如果當前幀是由構造方法或者實例方法創建,那么該對象引用this將會放在index為0的slot處

  • 三、操作數棧(operand stack) (掌握)

  • 每一個獨立的棧幀中除了包含局部變量表以外,還包含了一個后進先出的操作數棧,也可以稱之為表達式棧

  • 操作數棧,在方法執行過程中,根據字節碼指令,往棧中寫入數據或提取數據,即入棧或出棧

  • 如果被調用的方法帶有返回值的話,其返回值將會被壓入當前棧幀的操作數棧中

  • 操作數棧,主要用于保存計算機過程的中間結果,同時作為計算過程中變量臨時的存儲空間

  • 操作數棧的具體說明:

  • 解釋:




    四 、動態鏈接(Dynamic Linking)

  • 運行時常量池位于方法區,字節碼中的常量池結構如下:

  • 為什么需要常量池呢?
    (常量池的作用,就是為了提供一些符號和常量,便于指令的識別。下面提供一張測試類的運行時字節碼文件格式)

  • 每一個棧幀內部都包含一個指向運行時常量池Constant pool或該棧幀所屬方法的引用。包含這個引用的目的就是為了支持當前方法的代碼能夠實現動態鏈接。比如invokedynamic指令

  • 在Java源文件被編譯成字節碼文件中時,所有的變量和方法引用都作為符號引用(symbolic Refenrence)保存在class字節碼文件(javap反編譯查看)的常量池里。比如:描述一個方法調用了另外的其他方法時,就是通過常量池中指向方法的符號引用來表示的,那么動態鏈接的作用就是為了將這些符號引用(#)最終轉換為調用方法的直接引用。

  • 五、 方法的調用:(小插曲)難點

  • 靜態鏈接(早期綁定):當一個 字節碼文件被裝載進JVM內部時,如果被調用的目標方法在編譯期可知,且運行期保持不變時。這種情況下將調用方法的符號引用轉換為直接引用的過程稱之為靜態鏈接
    (invokestatic | invokespecial)

  • 動態鏈接(晚期綁定):如果被調用的方法在編譯期無法被確定下來,也就是說,只能夠在程序運行期將調用方法的符號引用轉換為直接引用,由于這種引用轉換過程具備動態性,因此也就被稱之為動態鏈接。體現了多態
    (invokevirtual | invokeinterface)

  • 非虛方法: 如果方法在編譯器就確定了具體的調用版本,這個版本在運行時是不可變的。這樣的方法稱為非虛方法
    (靜態方法、私有方法、final方法、實例構造器(實例已經確定,this()表示本類的構造器)、父類方法(super調用)都是非虛方法)

  • 其他所有體現多態特性的方法稱為虛方法

  • 如下指令要重點掌握

  • 普通調用指令:
    1.invokestatic:調用靜態方法,解析階段確定唯一方法版本;
    2.invokespecial:調用方法、私有及父類方法,解析階段確定唯一方法版本;
    3.invokevirtual:調用所有虛方法;
    4.invokeinterface:調用接口方法; 動態調用指令(Java7新增):
    5.invokedynamic:動態解析出需要調用的方法,然后執行 . 前四條指令固化在虛擬機內部,方法的調用執行不可人為干預,而invokedynamic指令則支持由 用戶確定方法版本。
    6.其中invokestatic指令和invokespecial指令調用的方法稱為非虛方法
    7.其中invokevirtual(final修飾的除外,JVM會把final方法調用也歸為invokevirtual指 令,但要注意final方法調用不是虛方法)、invokeinterface指令調用的方法稱稱為虛方法。

    /*** 解析調用中非虛方法、虛方法的測試*/ class Father {public Father(){System.out.println("Father默認構造器");}public static void showStatic(String s){System.out.println("Father show static"+s);}public final void showFinal(){System.out.println("Father show final");}public void showCommon(){System.out.println("Father show common");}}public class Son extends Father{public Son(){super();}public Son(int age){this();}public static void main(String[] args) {Son son = new Son();son.show();}//不是重寫的父類方法,因為靜態方法不能被重寫public static void showStatic(String s){System.out.println("Son show static"+s);}private void showPrivate(String s){System.out.println("Son show private"+s);}public void show(){//invokestaticshowStatic(" 大頭兒子");//invokestaticsuper.showStatic(" 大頭兒子");//invokespecialshowPrivate(" hello!");//invokespecialsuper.showCommon();//invokevirtual 因為此方法聲明有final 不能被子類重寫,所以也認為該方法是非虛方法showFinal();//虛方法如下//invokevirtualshowCommon();//沒有顯式加super,被認為是虛方法,因為子類可能重寫showCommoninfo();MethodInterface in = null;//invokeinterface 不確定接口實現類是哪一個 需要重寫in.methodA();}public void info(){}}interface MethodInterface {void methodA(); }

    六、 關于invokedynamic指令

  • JVM字節碼指令集一直比較穩定,一直到java7才增加了一個invokedynamic指令,這是Java為了實現【動態類型語言】支持而做的一種改進

  • 動態類型語言和靜態類型語言兩者的卻別就在于對類型的檢查是在編譯期還是在運行期,滿足前者就是靜態類型語言,反之則是動態類型語言。

  • Java是靜態類型語言(盡管lambda表達式為其增加了動態特性),js,python是動態類型語言

  • Java:String info = "小智";//靜態語言JS:var name = "小智“;var name = 10;//動態語言Pythom: info = 130;//更加徹底的動態語言

    七、方法返回地址(Return Address)

    理解如下話:

    (pc寄存器每執行一條指令都會被改變 而返回地址在調用call之前一直是上一條call后面的地址,不改變)

  • 存放調用該方法的PC寄存器的值
  • 執行引擎遇到任意一個方法返回的字節碼指令(return),會有返回值傳遞給上層的方法調用者,簡稱正常完成出口;
  • - 1.一個方法在正常調用完成之后究竟需要使用哪一個返回指令還需要根據方法返回值的實際 數據類型而定 - 2.在字節碼指令中,返回指令包含ireturn(當返回值是boolena、byte、char、short和int 類型時使用)、lreturn、freturn、dreturn以及areturn(引用類型的) - 3.另外還有一個return指令供聲明為void的方法、實例初始化方法、類和接口的初始化方法使用

  • 在方法執行的過程中遇到了異常(Exception),并且這個異常沒有在方法內進行處理,也就是只要在本方法的異常表中沒有搜素到匹配的異常處理器,就會導致方法退出,簡稱異常完成出口
  • 總結

    以上是生活随笔為你收集整理的JVM_03 运行时数据区 [ 虚拟机栈 ]的全部內容,希望文章能夠幫你解決所遇到的問題。

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