文章目录
前言
一、方法区
二、字节码二进制文件分析
三、动态链接
1、动态链接简介
2、静态链接与动态链接
3、早期绑定 和 晚期绑定
4、动态链接示例
前言
" 栈帧 " 中存储的是 局部变量表 , 操作数栈 , 动态链接 , 方法出口 ;
一、方法区
字节码文件加载到内存中后 , 该文件的 Class 会存放到 方法区 ( 元空间 ) 中 ; 方法区 中存储 静态变量 , 常量 , 类元信息 ;
类元信息 是由 方法和数据组成 ;
如果定义了一个静态变量类对象 , 那么方法区中 , 的该静态变量 指向了 堆 中的对象 ;
public static HelloWorld mHelloWorld = new HelloWorld();
如果在 方法的局部变量 中创建了 类对象 , 那么 线程栈 中的局部变量 , 也会指向 堆 中的对象 ;
public static void main(String[] args) { HelloWorld helloWorld = new HelloWorld(); helloWorld.add(); }
类 的 实例对象 创建完成后 , 除了在类中封装的成员之外 , 还包括 " 对象头 " ( Object Header ) ,
对象头 中包含 3 33 部分内容 :
数据区 ;
Marker Word 表及字段 ;
KlassPointer 类型指针 , 指向 方法区 ( 元空间 ) 中的 类元信息 的地址 ;
二、字节码二进制文件分析
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(); } }
字节码文件二进制数据分析 :
使用二进制查看工具查看 HelloWorld.class 字节码文件 , 这些二进制数值对应的就是 JVM 指令 ;
执行
javap -v HelloWorld.class
命令 , 命令行终端输出的就是字节码二进制数据的翻译内容 ;
major version: 52 配置 JDK 版本 ;
Constant pool 常量池 ;
D:\java>javap -v HelloWorld.class Classfile /D:/java/HelloWorld.class Last modified 2021-9-2; size 373 bytes MD5 checksum a9899195af11ef123968f811f4aa71f4 Compiled from "HelloWorld.java" public class HelloWorld minor version: 0 major version: 52 flags: 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: ()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 int add(); descriptor: ()I flags: ACC_PUBLIC Code: stack=2, locals=4, args_size=1 0: iconst_1 1: istore_1 2: iconst_1 3: istore_2 4: iload_1 5: iload_2 6: iadd 7: istore_3 8: iload_3 9: ireturn LineNumberTable: line 4: 0 line 5: 2 line 6: 4 line 7: 8 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=2, args_size=1 0: new #2 // class HelloWorld 3: dup 4: invokespecial #3 // Method "<init>":()V 7: astore_1 8: aload_1 9: invokevirtual #4 // Method add:()I 12: pop 13: return LineNumberTable: line 11: 0 line 12: 8 line 13: 13 } SourceFile: "HelloWorld.java"
三、动态链接
1、动态链接简介
动态链接 又称为 运行时常量池方法引用 ;
每个 方法 都有一个对应的 " 栈帧 " , 在栈帧 内部 的 " 动态链接 " 中 , 包含了 " 运行时常量池 " 中 栈帧对应方法的引用 , 该操作的目的是支持当前 方法 能 实现 动态链接 ;
2、静态链接与动态链接
静态链接 : 字节码文件加载到 Java 虚拟机内存后 , 如果在 编译阶段 就知道 目标方法 的 引用 , 并且在 运行时引用不变 , 那么调用方法时 , 直接使用 方法的符号引用 转为 直接引用 的过程 , 称为 静态链接 ;
动态链接 : 编译阶段 , 无法确定 被调用的方法 , 只能在 运行时 将 方法符号引用 转为 直接引用 , 这种 动态的引用转换 , 称为 动态链接 ;
3、早期绑定 和 晚期绑定
方法绑定 分为 早期绑定 和 晚期绑定 ;
早期绑定 : 被调用的方法在 编译期 可以知道 , 并且运行时保持不变 , 静态链接 ;
晚期绑定 : 被调用的方法 在 编译期 无法确定 , 在运行时动态地绑定相关方法 , 动态链接 ;
4、动态链接示例
动态链接指的是 , 将 Java 源码编译为 class 字节码文件后 , 方法调用 如 helloWorld.add() , 在 class 字节码文件中只是一个字符 , 在运行时 , 需要靠 " 动态链接 " 指向要运行的 helloWorld.add() 方法首地址 ;
" 动态链接 " 本质是 将 " 符号引用 " 转为 " 直接引用 " ;
在上述字节码 常量池 中 HelloWorld 类的 add 方法的引用如下 :
#4 = Methodref #2.#18 // HelloWorld.add:()I
#4 = Methodref 指向了 #2.#18 , #18 就是 add 方法 ; #18 = NameAndType #10:#11 // add:()I