JVM动态链接(Dynamic Linking)与常量池的作用

JVM动态链接(或指向运行时常量池的方法引用)

这里我用的是hotspot虚拟机

  1. 每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用,包含这个引用的目的就是为了支持当前方法的代码能够实现动态链接(Dynamic Linking)。比如:invokedynamic指令

  2. 在java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用(Symbolic Reference)保存在class文件的常量池里。
    比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用

    							  **JVM栈帧内部结构**
    

在这里插入图片描述
虚拟机栈: -> 栈帧—对应每个方法----> 包含: 局部变量表, 本地方法栈, 动态链接, 方法出口,

有些地方会把方法返回地址,动态链接,一些附加信息叫做帧数据区

public class DynamicLinkingTest {
     int num;
     String info;

    public void test1(){
        info="JVM";
        this.test2();
    }
    public void test2(){
        num=2;
    }
}

打开反编译后的字节码文件

public class com.qf.DynamicLinkingTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #7.#23         // java/lang/Object."<init>":()V
   #2 = String             #24            // JVM
   #3 = Fieldref           #6.#25         // com/qf/DynamicLinkingTest.info:Ljava/lang/String;
   #4 = Methodref          #6.#26         // com/qf/DynamicLinkingTest.test2:()V
   #5 = Fieldref           #6.#27         // com/qf/DynamicLinkingTest.num:I
   #6 = Class              #28            // com/qf/DynamicLinkingTest
   #7 = Class              #29            // java/lang/Object
   #8 = Utf8               num
   #9 = Utf8               I
  #10 = Utf8               info
  #11 = Utf8               Ljava/lang/String;
  #12 = Utf8               <init>
  #13 = Utf8               ()V
  #14 = Utf8               Code
  #15 = Utf8               LineNumberTable
  #16 = Utf8               LocalVariableTable
  #17 = Utf8               this
  #18 = Utf8               Lcom/qf/DynamicLinkingTest;
  #19 = Utf8               test1
  #20 = Utf8               test2
  #21 = Utf8               SourceFile
  #22 = Utf8               DynamicLinkingTest.java
  #23 = NameAndType        #12:#13        // "<init>":()V
  #24 = Utf8               JVM
  #25 = NameAndType        #10:#11        // info:Ljava/lang/String;
  #26 = NameAndType        #20:#13        // test2:()V
  #27 = NameAndType        #8:#9          // num:I
  #28 = Utf8               com/qf/DynamicLinkingTest
  #29 = Utf8               java/lang/Object
{
  int num;
    descriptor: I
    flags:

  java.lang.String info;
    descriptor: Ljava/lang/String;
    flags:

  public com.qf.DynamicLinkingTest();
    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 8: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/qf/DynamicLinkingTest;

  public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: ldc           #2                  // String JVM
         3: putfield      #3                  // Field info:Ljava/lang/String;
         6: aload_0
         7: invokevirtual #4                  // Method test2:()V
        10: return
      LineNumberTable:
        line 13: 0
        line 14: 6
        line 15: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   Lcom/qf/DynamicLinkingTest;

  public void test2();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: iconst_2
         2: putfield      #5                  // Field num:I
         5: return
      LineNumberTable:
        line 17: 0
        line 18: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/qf/DynamicLinkingTest;
}
SourceFile: "DynamicLinkingTest.java"

在这里插入图片描述
以Test1为例
我们可以看到 Code1里面有个#2
指向的是常量池里面的#2
我们定义的String类型赋值的JVM存储在这个位置
然后#2又指向了#24
这里的#xxx指向的都是常量池
在这里插入图片描述
在这里插入图片描述

当编译Java程序的时候,会得到程序中每一个类或者接口的独立的class文件。虽然独立看上去毫无关联,但是他们之间通过接口(harbor)符号互相联系,或者与Java API的class文件相联系。当运行程序的时候,Java虚拟机装载程序的类和接口,并且在动态连接的过程中把它们互相勾连起来。在程序运行中,Java虚拟机内部组织了一张互相连接的类和接口的网。

class把他们所有的引用符号放在一个地方——常量池。每一个class文件有一个常量池,每一个被Java虚拟机装载的类或者接口都有一份内部版本常量池,被称作运行时常量池。运行时常量池是特定与实现的数据结构,数据结构映射到class文件中的常量池。因此,当一个类型被首次装载的时候,所有来自于类型的符号引用都装载到了类型的运行时常量池。

在程序运行的过程中,如果某个特定的符号引用将要被使用,它首先要被解析。解析过程就是首先根据符号引用查找到实体,再把符号引用替换成直接引用的过程。因为所有的符号引用都是保存在常量池中,所以这种解析叫做常量池解析。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值