【Java 虚拟机原理】栈帧 | 动态链接 | 方法区 | 字节码文件二进制分析
文章目錄
- 前言
- 一、方法區(qū)
- 二、字節(jié)碼二進(jìn)制文件分析
- 三、動(dòng)態(tài)鏈接
- 1、動(dòng)態(tài)鏈接簡(jiǎn)介
- 2、靜態(tài)鏈接與動(dòng)態(tài)鏈接
- 3、早期綁定 和 晚期綁定
- 4、動(dòng)態(tài)鏈接示例
前言
" 棧幀 " 中存儲(chǔ)的是 局部變量表 , 操作數(shù)棧 , 動(dòng)態(tài)鏈接 , 方法出口 ;
一、方法區(qū)
字節(jié)碼文件加載到內(nèi)存中后 , 該文件的 Class 會(huì)存放到 方法區(qū) ( 元空間 ) 中 ; 方法區(qū) 中存儲(chǔ) 靜態(tài)變量 , 常量 , 類元信息 ;
類元信息 是由 方法和數(shù)據(jù)組成 ;
如果定義了一個(gè)靜態(tài)變量類對(duì)象 , 那么方法區(qū)中 , 的該靜態(tài)變量 指向了 堆 中的對(duì)象 ;
public static HelloWorld mHelloWorld = new HelloWorld();如果在 方法的局部變量 中創(chuàng)建了 類對(duì)象 , 那么 線程棧 中的局部變量 , 也會(huì)指向 堆 中的對(duì)象 ;
public static void main(String[] args) {HelloWorld helloWorld = new HelloWorld();helloWorld.add();}類 的 實(shí)例對(duì)象 創(chuàng)建完成后 , 除了在類中封裝的成員之外 , 還包括 " 對(duì)象頭 " ( Object Header ) ,
對(duì)象頭 中包含 333 部分內(nèi)容 :
- 數(shù)據(jù)區(qū) ;
- Marker Word 表及字段 ;
- KlassPointer 類型指針 , 指向 方法區(qū) ( 元空間 ) 中的 類元信息 的地址 ;
二、字節(jié)碼二進(jìn)制文件分析
Java 源代碼如下 :
public class HelloWorld {public static HelloWorld mHelloWorld = new HelloWorld();public int add() {int a = 1;int b = 1;int c = a + b;return c;}public static void main(String[] args) {HelloWorld helloWorld = new HelloWorld();helloWorld.add();} }字節(jié)碼文件二進(jìn)制數(shù)據(jù)分析 :
使用二進(jìn)制查看工具查看 HelloWorld.class 字節(jié)碼文件 , 這些二進(jìn)制數(shù)值對(duì)應(yīng)的就是 JVM 指令 ;
執(zhí)行
javap -v HelloWorld.class命令 , 命令行終端輸出的就是字節(jié)碼二進(jìn)制數(shù)據(jù)的翻譯內(nèi)容 ;
major version: 52 配置 JDK 版本 ;
Constant pool 常量池 ;
D:\java>javap -v HelloWorld.class Classfile /D:/java/HelloWorld.classLast modified 2021-9-2; size 373 bytesMD5 checksum a9899195af11ef123968f811f4aa71f4Compiled from "HelloWorld.java" public class HelloWorldminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER Constant pool:#1 = Methodref #5.#16 // java/lang/Object."<init>":()V#2 = Class #17 // HelloWorld#3 = Methodref #2.#16 // HelloWorld."<init>":()V#4 = Methodref #2.#18 // HelloWorld.add:()I#5 = Class #19 // java/lang/Object#6 = Utf8 <init>#7 = Utf8 ()V#8 = Utf8 Code#9 = Utf8 LineNumberTable#10 = Utf8 add#11 = Utf8 ()I#12 = Utf8 main#13 = Utf8 ([Ljava/lang/String;)V#14 = Utf8 SourceFile#15 = Utf8 HelloWorld.java#16 = NameAndType #6:#7 // "<init>":()V#17 = Utf8 HelloWorld#18 = NameAndType #10:#11 // add:()I#19 = Utf8 java/lang/Object {public HelloWorld();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 1: 0public int add();descriptor: ()Iflags: ACC_PUBLICCode:stack=2, locals=4, args_size=10: iconst_11: istore_12: iconst_13: istore_24: iload_15: iload_26: iadd7: istore_38: iload_39: ireturnLineNumberTable:line 4: 0line 5: 2line 6: 4line 7: 8public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new #2 // class HelloWorld3: dup4: invokespecial #3 // Method "<init>":()V7: astore_18: aload_19: invokevirtual #4 // Method add:()I12: pop13: returnLineNumberTable:line 11: 0line 12: 8line 13: 13 } SourceFile: "HelloWorld.java"三、動(dòng)態(tài)鏈接
1、動(dòng)態(tài)鏈接簡(jiǎn)介
動(dòng)態(tài)鏈接 又稱為 運(yùn)行時(shí)常量池方法引用 ;
每個(gè) 方法 都有一個(gè)對(duì)應(yīng)的 " 棧幀 " , 在棧幀 內(nèi)部 的 " 動(dòng)態(tài)鏈接 " 中 , 包含了 " 運(yùn)行時(shí)常量池 " 中 棧幀對(duì)應(yīng)方法的引用 , 該操作的目的是支持當(dāng)前 方法 能 實(shí)現(xiàn) 動(dòng)態(tài)鏈接 ;
2、靜態(tài)鏈接與動(dòng)態(tài)鏈接
靜態(tài)鏈接 : 字節(jié)碼文件加載到 Java 虛擬機(jī)內(nèi)存后 , 如果在 編譯階段 就知道 目標(biāo)方法 的 引用 , 并且在 運(yùn)行時(shí)引用不變 , 那么調(diào)用方法時(shí) , 直接使用 方法的符號(hào)引用 轉(zhuǎn)為 直接引用 的過程 , 稱為 靜態(tài)鏈接 ;
動(dòng)態(tài)鏈接 : 編譯階段 , 無法確定 被調(diào)用的方法 , 只能在 運(yùn)行時(shí) 將 方法符號(hào)引用 轉(zhuǎn)為 直接引用 , 這種 動(dòng)態(tài)的引用轉(zhuǎn)換 , 稱為 動(dòng)態(tài)鏈接 ;
3、早期綁定 和 晚期綁定
方法綁定 分為 早期綁定 和 晚期綁定 ;
早期綁定 : 被調(diào)用的方法在 編譯期 可以知道 , 并且運(yùn)行時(shí)保持不變 , 靜態(tài)鏈接 ;
晚期綁定 : 被調(diào)用的方法 在 編譯期 無法確定 , 在運(yùn)行時(shí)動(dòng)態(tài)地綁定相關(guān)方法 , 動(dòng)態(tài)鏈接 ;
4、動(dòng)態(tài)鏈接示例
動(dòng)態(tài)鏈接指的是 , 將 Java 源碼編譯為 class 字節(jié)碼文件后 , 方法調(diào)用 如 helloWorld.add() , 在 class 字節(jié)碼文件中只是一個(gè)字符 , 在運(yùn)行時(shí) , 需要靠 " 動(dòng)態(tài)鏈接 " 指向要運(yùn)行的 helloWorld.add() 方法首地址 ;
" 動(dòng)態(tài)鏈接 " 本質(zhì)是 將 " 符號(hào)引用 " 轉(zhuǎn)為 " 直接引用 " ;
在上述字節(jié)碼 常量池 中 HelloWorld 類的 add 方法的引用如下 :
#4 = Methodref #2.#18 // HelloWorld.add:()I#4 = Methodref 指向了 #2.#18 , #18 就是 add 方法 ;
#18 = NameAndType #10:#11 // add:()I總結(jié)
以上是生活随笔為你收集整理的【Java 虚拟机原理】栈帧 | 动态链接 | 方法区 | 字节码文件二进制分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 虚拟机原理】栈帧 | 局部变
- 下一篇: 【Google Play】APK 扩展包