深入理解JVM虚拟机第二十四篇:详解JVM当中的动态链接和常量池的作用

大神链接:作者有幸结识技术大神孙哥为好友,获益匪浅。现在把孙哥视频分享给大家。

孙哥链接:孙哥个人主页
作者简介:一个颜值99分,只比孙哥差一点的程序员
本专栏简介:话不多说,让我们一起干翻JVM

本文章简介:话不多说,让我们讲清楚JVM当中与操作数栈相关的动态链接和常量池的作用

文章目录

知识回顾

1:栈帧中的结构图解

2:结构概念回顾 

一:动态链接

1:动态链接概念

2:编写代码证明

3:源代码的Javap

二:常量池

1:常量池的概念

2:说明


知识回顾

1:栈帧中的结构图解

2:结构概念回顾 

         栈帧中的几部分大致可以分为这几个:局部变量表,操作数栈,动态链接,方法返回地址,一些附加信息。

        局部变量表,操作数栈我们都已经详细的分析过了,接下来,我们该分享动态链接了。

        值得一提的是:方法返回地址,动态链接和一些附加信息在有一些地方被称为帧数据区。这个概念主要在一些教材上是这样提到的,我们也需要知道。

一:动态链接

1:动态链接概念

        动态链接又称为:执行运行时常量池的方法引用。

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

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

        常量池就是我们的类被加载的时候所需要的信息,类、属性、方法的各种信息都会使用符号的形式声明出来,这是对类中各类数据的一个描述,而这个描述基于符号引用进行存储到了常量池这个区域。

        而在栈帧中的字节码区域,字节码指令后边跟着一堆符号,这些符号就是常量池中的符号索引。这样就是所谓的:执行运行时常量池的方法引用。

        常量池就是字节码整理后的那个区域,常量池当方法运行时会进入到方法区当中,此时的常量池就被称为运行时常量池。

        动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用 

        这一有一个问题,为什么要通过动态链接这种方式,而不是直接通过将数据直接放到引用的位置形成直接引用呢? 

        我们这样做的目的是为了保证相同数据只有一份,不同地方使用只需要添加引用即可。节约空间。提升运行效率。

        为什么需要这个运行时常量池呢?运行时常量池就是把字节码中的常量池加载到了方法区中,没有这个运行时常量池也行,采用直接引用即可,但是这样就回到了上边的问题。

        所以为什么需要常量池呢?
        动态链接和常量池的作用,就是为了提供一些符号和常量,便于指令的识别。

2:编写代码证明

/*** @author Administrator*/
public class DynamicLInkingTest {int num = 10;public void methodA(){System.out.println("methodA().....");}public void methodB(){System.out.println("methodB().....");methodA();num++;}
}

3:源代码的Javap

        基于Javap对字节码进行整理,按照格式进行输出。

PS D:\code\study\hadoop\shit\target\classes> javap -v .\DynamicLInkingTest.class
Classfile /D:/code/study/hadoop/shit/target/classes/DynamicLInkingTest.classLast modified 2023年11月12日; size 678 bytesSHA-256 checksum acf0e245362759ceb374039c92493caf8913ff898697f7735b6ddedb262d2bd7Compiled from "DynamicLInkingTest.java"
public class DynamicLInkingTestminor version: 0major version: 52flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #8                          // DynamicLInkingTestsuper_class: #9                         // java/lang/Objectinterfaces: 0, fields: 1, methods: 3, attributes: 1
Constant pool:#1 = Methodref          #9.#23         // java/lang/Object."<init>":()V#2 = Fieldref           #8.#24         // DynamicLInkingTest.num:I#3 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;#4 = String             #27            // methodA().....#5 = Methodref          #28.#29        // java/io/PrintStream.println:(Ljava/lang/String;)V#6 = String             #30            // methodB().....#7 = Methodref          #8.#31         // DynamicLInkingTest.methodA:()V#8 = Class              #32            // DynamicLInkingTest#9 = Class              #33            // java/lang/Object#10 = Utf8               num#11 = Utf8               I#12 = Utf8               <init>#13 = Utf8               ()V#14 = Utf8               Code#15 = Utf8               LineNumberTable#16 = Utf8               LocalVariableTable#17 = Utf8               this#18 = Utf8               LDynamicLInkingTest;#19 = Utf8               methodA#20 = Utf8               methodB#21 = Utf8               SourceFile#22 = Utf8               DynamicLInkingTest.java#23 = NameAndType        #12:#13        // "<init>":()V#24 = NameAndType        #10:#11        // num:I#25 = Class              #34            // java/lang/System#26 = NameAndType        #35:#36        // out:Ljava/io/PrintStream;#27 = Utf8               methodA().....#28 = Class              #37            // java/io/PrintStream#29 = NameAndType        #38:#39        // println:(Ljava/lang/String;)V#30 = Utf8               methodB().....#31 = NameAndType        #19:#13        // methodA:()V#32 = Utf8               DynamicLInkingTest#33 = Utf8               java/lang/Object#34 = Utf8               java/lang/System#35 = Utf8               out#36 = Utf8               Ljava/io/PrintStream;#37 = Utf8               java/io/PrintStream#38 = Utf8               println#39 = Utf8               (Ljava/lang/String;)V
{int num;descriptor: Iflags: (0x0000)public DynamicLInkingTest();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1                  // Method java/lang/Object."<init>":()V4: aload_05: bipush        107: putfield      #2                  // Field num:I10: returnLineNumberTable:line 4: 0line 6: 4LocalVariableTable:Start  Length  Slot  Name   Signature0      11     0  this   LDynamicLInkingTest;public void methodA();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=2, locals=1, args_size=10: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc           #4                  // String methodA().....5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 9: 0line 10: 8LocalVariableTable:Start  Length  Slot  Name   Signature0       9     0  this   LDynamicLInkingTest;public void methodB();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=3, locals=1, args_size=10: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc           #6                  // String methodB().....5: invokevirtual #5                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: aload_09: invokevirtual #7                  // Method methodA:()V12: aload_013: dup14: getfield      #2                  // Field num:I17: iconst_118: iadd19: putfield      #2                  // Field num:I22: returnLineNumberTable:line 13: 0line 15: 8line 17: 12line 18: 22LocalVariableTable:Start  Length  Slot  Name   Signature0      23     0  this   LDynamicLInkingTest;
}
SourceFile: "DynamicLInkingTest.java"

        我们关注一下methodB方法的内容:

        我们截取其中的一行的字节码指令,3是地址,或者应该叫偏移地址。ldc是具体的偏移地址下的字节码指令。

         3: ldc           #6                  // String methodB().....

二:常量池

1:常量池的概念

        常量池就是我们的类被加载的时候所需要的信息,类、属性、方法的各种信息都会使用符号的形式声明出来,#1=Methodref后边可能继续是符号引用或者是真实的数据。总之跟着符号索引一定可以找到最终的真实数据,这是对类中各类数据的一个描述,而这个描述基于符号引用进行处处到了常量池这个区域。

        而在栈帧中的字节码区域,字节码指令后边跟着一堆符号,这些符号就是常量池中的符号索引。这样就是所谓的:执行运行时常量池的方法引用。

Constant pool:#1 = Methodref          #9.#23         // java/lang/Object."<init>":()V#2 = Fieldref           #8.#24         // DynamicLInkingTest.num:I#3 = Fieldref           #25.#26        // java/lang/System.out:Ljava/io/PrintStream;#4 = String             #27            // methodA().....#5 = Methodref          #28.#29        // java/io/PrintStream.println:(Ljava/lang/String;)V#6 = String             #30            // methodB().....#7 = Methodref          #8.#31         // DynamicLInkingTest.methodA:()V#8 = Class              #32            // DynamicLInkingTest#9 = Class              #33            // java/lang/Object#10 = Utf8               num#11 = Utf8               I#12 = Utf8               <init>#13 = Utf8               ()V#14 = Utf8               Code#15 = Utf8               LineNumberTable#16 = Utf8               LocalVariableTable#17 = Utf8               this#18 = Utf8               LDynamicLInkingTest;#19 = Utf8               methodA#20 = Utf8               methodB#21 = Utf8               SourceFile#22 = Utf8               DynamicLInkingTest.java#23 = NameAndType        #12:#13        // "<init>":()V#24 = NameAndType        #10:#11        // num:I#25 = Class              #34            // java/lang/System#26 = NameAndType        #35:#36        // out:Ljava/io/PrintStream;#27 = Utf8               methodA().....#28 = Class              #37            // java/io/PrintStream#29 = NameAndType        #38:#39        // println:(Ljava/lang/String;)V#30 = Utf8               methodB().....#31 = NameAndType        #19:#13        // methodA:()V#32 = Utf8               DynamicLInkingTest#33 = Utf8               java/lang/Object#34 = Utf8               java/lang/System#35 = Utf8               out#36 = Utf8               Ljava/io/PrintStream;#37 = Utf8               java/io/PrintStream#38 = Utf8               println#39 = Utf8               (Ljava/lang/String;)V

2:说明

        当前我们只需要常量池对应了哪块区域即可,后边我们会详细的进行剖析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/142274.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在虚拟环境下安装python包

PyCharm可以自己给项目创建虚拟环境&#xff0c;示例如下&#xff1a; 首先通过File—>Setting—>Project&#xff1a;【项目名称】—>Project Interpreter—>设置—>add—>Virtuallenv Environment配置虚拟环境即可 添加解释器&#xff1a; 当创建虚拟环…

sqli-labs关卡13(基于post提交的单引号加括号的报错盲注)通关思路

文章目录 前言一、回顾第十二关知识点二、靶场第十三关通关思路1、判断注入点2、爆显位3、爆数据库名4、爆数据库表5、爆数据库列6、爆数据库关键信息 总结 前言 此文章只用于学习和反思巩固sql注入知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;…

c++范围for语句

语法格式 for(declaration:expression)statement 基本使用 遍历输出 vector<int> nums { 1,2,3,4,5}; for (int num : nums) {num;cout << num << " "; } cout << endl; 遍历时修改 vector<int> nums { 1,2,3,4,5}; for (int&…

浏览器Cookie是什么?如何在MaskFog指纹浏览器中导入Cookie?

在使用互联网时我们常常听到cookie这个词&#xff0c;那到底什么是cookie呢&#xff1f; Cookie是某些网站为了辨别用户身份而储存在用户本地终端上的数据&#xff08;通常经过加密&#xff09;&#xff0c;由用户客户端计算机暂时或永久保存的信息客户端向服务器发起请求&…

Python使用带账密的Socks5代理

测试代码如下 import requestsip 146.78.85.145 port 9527 username ********* password ********* proxies {http: fsocks5://{username}:{password}{ip}:{port},https: fsocks5://{username}:{password}{ip}:{port} } print(proxies) body requests.get("https:/…

OpenCV中更稳更快的边缘检测方法,快速查找线、圆、椭圆--EdgeDrawing-C++代码

计算机视觉之家看到快速圆检测Edge Drawing&#xff0c;其效果比霍夫要好&#xff0c;速度更快&#xff08;具体效果可以参考视觉之家的文章&#xff09;&#xff0c;上面C代码不全&#xff0c;那么好的检测效果国内资料竟然那么少&#xff0c;后在opencv的开发文档中找到了C代…

C++中的四种构造函数

在C中&#xff0c;有几种不同类型的构造函数&#xff0c;基于它们的特性和用途&#xff0c;可以将它们分类为以下四种&#xff1a; 默认构造函数&#xff08;Default Constructor&#xff09;: 如果没有为类定义任何构造函数&#xff0c;编译器将为其提供一个默认构造函数。这种…

基于单片机的塑料厂房气体检测系统设计

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、设计的主要内容二、系统硬件设计三、软件设计实物 四、结论五、 文章目录 概要 本文首先分析了基于单片机的可燃…

【计算机网络】UDP协议

UDP的结构 我们学习一个协议最主要的就是理解它的报文格式&#xff0c;对于UDP协议来说 我们看下面的这张图。 16位UDP长度&#xff0c;表示整个数据报&#xff08;UDP首部UDP数据&#xff09;的最大长度。UDP报文长度占两个字节&#xff0c;16位表示的数据范围&#xff08;0-…

java数据结构--二叉树

目录 一.概念 二.构建二叉树节点类TreeNode 三.二叉树的遍历 1.前序遍历preOrder 2.中序遍历medOrder 3.后序遍历postOrder 4.非递归遍历 三.深度 1.概念 2.递归求最大深度 3.层序遍历加队列求最大深度 4.测试 5.递归求最小深度 6.层序遍历加队列求最小深度 7.测试 四…

【保姆级教程】Linux安装JDK8

本文以centos7为例&#xff0c;一步一步进行jdk1.8的安装。 1. 下载安装 官网下载链接&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/#java8 上传jdk的压缩包到服务器的/usr/local目录下 在当前目录解压jdk压缩包&#xff0c;如果是其它版本&#xf…

设计模式 -- 代理模式(Proxy Pattern)

代理模式&#xff1a;一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。 在代理模式中&#xff0c;我们创建具有现有对象的对象&#xff0c;以便向外界提供功能接口。 介绍 意图&#xff1a;为其他对象提供一种代理以控制对这个对象的访问。主要解决问题&#xf…

基于LoongArch指令集-五级流水线CPU 乘除法指令的添加

调用Xilinx IP实现乘除法运算部件 调用Xilinx IP实现乘法运算部件 wire [31:0] src1,src2; wire [63:0] unsigned_prod; wire [63:0] signed_prod;assign unsigned_prod src1*src2; assign signed_prod $signed(src1)*$signed(src2);调用 Xilinx IP 实现除法运算部件 在工程…

Trie 前缀树 字典树

PreFix Tree 二叉树 的每个节点只有两个孩子,那如果每个节点可以有多个孩子呢?这就形成了「多叉树」。多叉树的子节点数目一般不是固定的,所以会用变长数组来保存所有的子节点的指针。 「前缀树」是一种特殊的多叉树,它的 TrieNode 中 chidren 是一个大小为 26 的一维数组…

自压缩llm 为 超长记忆

自压缩llm 为 超长记忆 解释数据处理实际例子解释 # 自压缩llm 为 超长记忆 # prompt 格式 # <|细颗粒词表|><|粗颗粒词表|><|细颗粒词表|> # 细颗粒词表 = 词1,词2,词3,词4,词5,词6,词7,词8,词9,词10, # 组颗粒词表id1, 组颗粒词表id2, 组颗粒…

一篇博客读懂队列——Queue

目录 一、队列的概念和结构 ​二、队列的实现 2.1队列的初始化QueueInit 2.2队列的摧毁QueueDestroy 2.3插入结点QueuePush 2.4删除结点QueuePop 2.5返回队头QueueFront 2.6返回队尾QueueBack 2.7判断队列为空QueueEmpty 2.8统计队列数目QueueSize 一、队列的概念和…

C#动态数据类型

static void Main(string[] args){dynamic point new {x 15,y 10};DrwaPoint(point);System.Console.Read();}static void DrwaPoint(dynamic point) >System.Console.WriteLine($"x:{point.x},y:{point.y}");

【nlp】1.4 文本特征处理(n-gram特征、文本长度规范:补齐与截断)

文本特征处理 1 什么是n-gram特征2 文本长度规范及其作用文本特征处理的作用: 文本特征处理包括为语料添加具有普适性的文本特征,如:n-gram特征,以及对加入特征之后的文本语料进行必要的处理, 如: 长度规范。这些特征处理工作能够有效的将重要的文本特征加入模型训练中,增强…

设计模式介绍

写在前面的话 以前也学习过设计模式&#xff0c;但是总感觉学不懂&#xff0c;最近开发项目深刻感受到设计模式的重要性&#xff0c;系统学习一些。 我是观看油管上李建忠老师的视频学习做的总结&#xff0c;会不断补充&#xff0c;欢迎大家指出错误&#xff0c;学习进步。 …

k8s ----对外暴露

目录 一、Ingress 简介 1、Ingress 组成 2、Ingress 工作原理 二、部署Ingress 1、部署 nginx-ingress-controller 2、暴露ingress 4.1 DaemonSetHostNetworknodeSelector模式的service 4.2 DeploymentNodePort模式的Service 三、Ingress HTTP 代理访问 四、Ingress …