【Java 虚拟机原理】栈帧 | 动态链接 | 方法区 | 字节码文件二进制分析

简介: 【Java 虚拟机原理】栈帧 | 动态链接 | 方法区 | 字节码文件二进制分析

文章目录

前言

一、方法区

二、字节码二进制文件分析

三、动态链接

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 类型指针 , 指向 方法区 ( 元空间 ) 中的 类元信息 的地址 ;


image.png





二、字节码二进制文件分析


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 指令 ;

image.png



执行


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"


image.png





三、动态链接



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



目录
相关文章
|
1月前
|
Java
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
java小工具util系列5:java文件相关操作工具,包括读取服务器路径下文件,删除文件及子文件,删除文件夹等方法
74 9
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
17天前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
80 34
|
3天前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
14 3
|
1天前
|
Rust 安全 Java
JVM原理与实现——Synchronized关键字
在多线程Java程序中,`Synchronized`关键字用于确保线程安全。本文深入探讨其工作原理,通过分析字节码`monitorenter`和`monitorexit`,解释JVM如何实现同步机制。文章展示了`Synchronized`方法的编译结果,并详细解析了轻量锁和重度锁的实现过程,包括Mark Word的状态变化及CAS操作的应用。最后简要介绍了`ObjectMonitor::enter()`函数在获取重度锁时的作用。
JVM原理与实现——Synchronized关键字
|
3天前
|
安全 算法 Java
Java CAS原理和应用场景大揭秘:你掌握了吗?
CAS(Compare and Swap)是一种乐观锁机制,通过硬件指令实现原子操作,确保多线程环境下对共享变量的安全访问。它避免了传统互斥锁的性能开销和线程阻塞问题。CAS操作包含三个步骤:获取期望值、比较当前值与期望值是否相等、若相等则更新为新值。CAS广泛应用于高并发场景,如数据库事务、分布式锁、无锁数据结构等,但需注意ABA问题。Java中常用`java.util.concurrent.atomic`包下的类支持CAS操作。
21 2
|
1月前
|
消息中间件 存储 Java
RocketMQ文件刷盘机制深度解析与Java模拟实现
【11月更文挑战第22天】在现代分布式系统中,消息队列(Message Queue, MQ)作为一种重要的中间件,扮演着连接不同服务、实现异步通信和消息解耦的关键角色。Apache RocketMQ作为一款高性能的分布式消息中间件,广泛应用于实时数据流处理、日志流处理等场景。为了保证消息的可靠性,RocketMQ引入了一种称为“刷盘”的机制,将消息从内存写入到磁盘中,确保消息持久化。本文将从底层原理、业务场景、概念、功能点等方面深入解析RocketMQ的文件刷盘机制,并使用Java模拟实现类似的功能。
42 3
|
1月前
|
Java 测试技术 Maven
Maven clean 提示文件 java.io.IOException
在使用Maven进行项目打包时,遇到了`Failed to delete`错误,尝试手动删除目标文件也失败,提示`java.io.IOException`。经过分析,发现问题是由于`sys-info.log`文件被其他进程占用。解决方法是关闭IDEA和相关Java进程,清理隐藏的Java进程后重新尝试Maven clean操作。最终问题得以解决。总结:遇到此类问题时,可以通过任务管理器清理相关进程或重启电脑来解决。
|
1月前
|
Ubuntu 网络安全 虚拟化
VMware虚拟机ping不通原因排查及分析
下面以 VMware 虚拟机为例进行介绍。
722 3
|
1月前
|
存储 SQL 数据库
虚拟化数据恢复—Vmware虚拟机误还原快照的数据恢复案例
虚拟化数据恢复环境: 一台虚拟机从物理机迁移到ESXI虚拟化平台,迁移完成后做了一个快照。虚拟机上运行了一个SQL Server数据库,记录了数年的数据。 ESXI虚拟化平台上有数十台虚拟机,EXSI虚拟化平台连接了一台EVA存储,所有的虚拟机都存放在EVA存储上。 虚拟化故障: 工组人员误操作将数年前迁移完成后做的快照还原了,也就意味着虚拟机状态还原到数年前,近几年数据都被删除了。 还原快照相当于删除数据,意味着部分存储空间会被释放。为了不让这部分释放的空间被重用,需要将连接到这台存储的所有虚拟机都关掉,需要将不能长时间宕机的虚拟机迁移到别的EXSI虚拟化平台上。
109 50