20.JVM棧幀的內部結構-動態鏈接(Dynamic Linking)

1.動態鏈接(指向運行時常量池的方法引用)

1.動態鏈接又稱爲指向運行時常量池的方法引用
2.一個方法對應一個棧幀。每一個棧幀中都包含一個指向運行時常量池中該棧幀所屬方法的引用。
3.Java源文件被編譯到字節碼文件中時,所有的變量方法引用都作爲符號引用(Symbolic Reference)保存在class文件的常量池裏。例如:描述一個方法調用了另外其他的方法時,就是通過常量池中指向方法的符號引用來表示的,動態鏈接的作用是爲了將這些符號引用轉換爲調用方法的直接引用。
在這裏插入圖片描述
如下圖所示,每一個線程都有自己的PC計數器、本地方法棧、虛擬機棧。虛擬機棧中存儲的是一個個棧幀,棧幀中包含局部變量表、方法返回地址、操作數棧、動態鏈接(指向運行時常量池的方法引用)。
圖中Constant Pool Reference就是動態鏈接,指向的是方法區中運行時常量池的方法引用(method reference)。
在這裏插入圖片描述
例子:

package jvn;
public class DynamicLinkingTest {
    int num = 10;
    public void methodA(){
        System.out.println("methodA()....");
    }
    public void methodB(){
        System.out.println("methodB()....");
        methodA();
        num++;
    }
}

使用javap -v DynamicLinkingTest 反編譯上面的java代碼產生的class文件。得到下面的字節碼輸出。
1.其中的Constant pool就是常量池,當程序運行起來的時候,就是運行時常量池。
2.第一列#1,#2等等,這些就是符號引用。
3.methodB調用methodA對應的指令是9: invokevirtual #36 // Method methodA:()V
4.爲什麼需要常量池?
常量池的作用就是爲了提供一些符號和常量,便於指令的識別。

C:\Users\12558>javap -v D:\Eclipse_workspace\JVM\jvn\bin\jvn\DynamicLinkingTest.class
Classfile /D:/Eclipse_workspace/JVM/jvn/bin/jvn/DynamicLinkingTest.class
  Last modified 2020-7-5; size 688 bytes
  MD5 checksum 7c8d5b298eaf82e8891ad1de67e14fbd
  Compiled from "DynamicLinkingTest.java"
public class jvn.DynamicLinkingTest
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Class              #2             // jvn/DynamicLinkingTest
   #2 = Utf8               jvn/DynamicLinkingTest
   #3 = Class              #4             // java/lang/Object
   #4 = Utf8               java/lang/Object
   #5 = Utf8               num
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Methodref          #3.#11         // java/lang/Object."<init>":()V
  #11 = NameAndType        #7:#8          // "<init>":()V
  #12 = Fieldref           #1.#13         // jvn/DynamicLinkingTest.num:I
  #13 = NameAndType        #5:#6          // num:I
  #14 = Utf8               LineNumberTable
  #15 = Utf8               LocalVariableTable
  #16 = Utf8               this
  #17 = Utf8               Ljvn/DynamicLinkingTest;
  #18 = Utf8               methodA
  #19 = Fieldref           #20.#22        // java/lang/System.out:Ljava/io/PrintStream;
  #20 = Class              #21            // java/lang/System
  #21 = Utf8               java/lang/System
  #22 = NameAndType        #23:#24        // out:Ljava/io/PrintStream;
  #23 = Utf8               out
  #24 = Utf8               Ljava/io/PrintStream;
  #25 = String             #26            // methodA()....
  #26 = Utf8               methodA()....
  #27 = Methodref          #28.#30        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #28 = Class              #29            // java/io/PrintStream
  #29 = Utf8               java/io/PrintStream
  #30 = NameAndType        #31:#32        // println:(Ljava/lang/String;)V
  #31 = Utf8               println
  #32 = Utf8               (Ljava/lang/String;)V
  #33 = Utf8               methodB
  #34 = String             #35            // methodB()....
  #35 = Utf8               methodB()....
  #36 = Methodref          #1.#37         // jvn/DynamicLinkingTest.methodA:()V
  #37 = NameAndType        #18:#8         // methodA:()V
  #38 = Utf8               SourceFile
  #39 = Utf8               DynamicLinkingTest.java
{
  int num;
    descriptor: I
    flags:

  public jvn.DynamicLinkingTest();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #10                 // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #12                 // Field num:I
        10: return
      LineNumberTable:
        line 3: 0
        line 5: 4
        line 3: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      11     0  this   Ljvn/DynamicLinkingTest;

  public void methodA();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #25                 // String methodA()....
         5: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
         8: return
      LineNumberTable:
        line 8: 0
        line 9: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Ljvn/DynamicLinkingTest;

  public void methodB();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: getstatic     #19                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #34                 // String methodB()....
         5: invokevirtual #27                 // Method java/io/PrintStream.println:(Ljava/lang/St
ring;)V
         8: aload_0
         9: invokevirtual #36                 // Method methodA:()V
        12: aload_0
        13: dup
        14: getfield      #12                 // Field num:I
        17: iconst_1
        18: iadd
        19: putfield      #12                 // Field num:I
        22: return
      LineNumberTable:
        line 12: 0
        line 14: 8
        line 16: 12
        line 17: 22
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      23     0  this   Ljvn/DynamicLinkingTest;
}
SourceFile: "DynamicLinkingTest.java"

更多JVM文章請參考我的JVM專欄:
https://blog.csdn.net/u011069294/category_10113093.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章