JVM中常量池和运行时常量池、字符串常量池三者之间的关系
文章目录
- 前言
- 常量池(Constant Pool)
- 运行时常量池(Runtime Constant Pool)
- 字符串常量池(String Literal Pool)
- 运行时常量池和字符串常量池位置变化
- 方法区与永久代和元空间的关系
- 三者之间的关系
- 常量池与运行时常量池
- 运行时常量池与字符串常量池
- 总结
前言
在Java虚拟机(JVM)中,常量池、运行时常量池和字符串常量池是三个相关但又有所区别的概念。下面详细解释这三个概念及其相互的联系。
常量池(Constant Pool)
常量池也被称为 Class 文件常量池,是指每个 Java 类编译后的 .class 文件中的一个表结构,每个类文件(.class 文件)都有一个独立的常量池(Constant Pool)。
它存储了类或接口在编译时已知的各种字面量和符号引用。这些信息包括但不限于:
- 字面量:如整数、浮点数、字符串等。
- 符号引用:如类和接口的全限定名、字段名称和描述符、方法名称和描述符等。这些符号引用在类加载过程中会被解析为直接引用,从而让 JVM 能够准确地定位和调用相关的类、字段和方法。
每个类或接口都有其对应的常量池,它是类加载过程中不可或缺的一部分,用于解析类中的各种引用。
特点:常量池是静态的,在编译阶段就已经确定,存储在 .class 文件中,它是 JVM 后续加载和使用类的重要数据基础。
代码
public class HelloWorld {public static void main(String[] args) {System.out.println("hello world");}
}
通过反编译查看以上代码的.class文件
输入javap -v HelloWorld.class查看类文件的常量池内容:
Classfile /D:/Test/jvm/out/production/jvm/cn/qf/HelloWorld.classLast modified 2024-12-6; size 567 bytesMD5 checksum 8efebdac91aa496515fa1c161184e354Compiled from "HelloWorld.java"
public class cn.qf.HelloWorldminor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref #6.#20 // java/lang/Object."<init>":()V#2 = Fieldref #21.#22 // java/lang/System.out:Ljava/io/PrintStream;#3 = String #23 // hello world#4 = Methodref #24.#25 // java/io/PrintStream.println:(Ljava/lang/String;)V#5 = Class #26 // cn/qf//HelloWorld#6 = Class #27 // java/lang/Object#7 = Utf8 <init>#8 = Utf8 ()V#9 = Utf8 Code#10 = Utf8 LineNumberTable#11 = Utf8 LocalVariableTable#12 = Utf8 this#13 = Utf8 Lcn/qf//HelloWorld;#14 = Utf8 main#15 = Utf8 ([Ljava/lang/String;)V#16 = Utf8 args#17 = Utf8 [Ljava/lang/String;#18 = Utf8 SourceFile#19 = Utf8 HelloWorld.java#20 = NameAndType #7:#8 // "<init>":()V#21 = Class #28 // java/lang/System#22 = NameAndType #29:#30 // out:Ljava/io/PrintStream;#23 = Utf8 hello world#24 = Class #31 // java/io/PrintStream#25 = NameAndType #32:#33 // println:(Ljava/lang/String;)V#26 = Utf8 cn/qf/HelloWorld#27 = Utf8 java/lang/Object#28 = Utf8 java/lang/System#29 = Utf8 out#30 = Utf8 Ljava/io/PrintStream;#31 = Utf8 java/io/PrintStream#32 = Utf8 println#33 = Utf8 (Ljava/lang/String;)V
{public cn.qf.HelloWorld();descriptor: ()Vflags: ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 4: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lcn/qf/HelloWorld;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=10: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #3 // String hello world5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 6: 0line 7: 8LocalVariableTable:Start Length Slot Name Signature0 9 0 args [Ljava/lang/String;
}
SourceFile: "HelloWorld.java"
重点观察Constant pool
运行时常量池(Runtime Constant Pool)
运行时常量池是每一个类或接口的常量池表的一个运行时表示形式,运行时常量池是方法区的一部分。
在Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有用于存放编译期生成的各种字面量(Literal)和符号引用(Symbolic Reference)的 常量池表(Constant Pool Table) 。
当JVM加载一个类文件时,会将该类的常量池信息(常量池表)加载到方法区内的运行时常量池中。
字符串常量池(String Literal Pool)
字符串常量池是专门用于存放程序中使用String字面量创建的字符串对象的一个特殊区域。
在JDK 6及之前,字符串常量池是运行时常量池的一部分,而JDK 7及之后字符串常量池被移到堆中,因此字符串常量池不再是严格意义上的运行时常量池的一部分。
字符串常量池特别针对字符串进行了优化设计,以实现字符串共享,减少内存占用。
它是一个类似于哈希表(HashTable)的数据结构,在 HotSpot 虚拟机中由StringTable 类实现。
- 作用:节省内存空间,提高性能。
- 位置:与运行时常量池类似,在JDK 7之前位于永久代,在JDK 7及之后被移到了堆中。
运行时常量池和字符串常量池位置变化
JDK1.7 之前,方法区的具体实现是永久代(Permanent Generation),运行时常量池和字符串常量池存放在方法区(永久代)。

JDK 7 开始,字符串常量池和静态变量从永久代中移动到了 Java 堆中,运行时常量池不变。方法区仍然由永久代实现。
这一改变主要是为了避免永久代的内存溢出问题,因为永久代的空间相对较小,且难以进行调优,而堆的管理相对更加灵活。

JDK 8 及以后的版本中,永久代被元空间(Metaspace)所取代(运行时常量池还是在方法区中),但字符串常量池仍然在堆中。
元空间使用的是本地内存,不再受 JVM 堆内存的限制。方法区由元空间实现,它主要存储类的元数据信息,而字符串常量池独立于元空间,在堆中进行管理。
方法区与永久代和元空间的关系
方法区和永久代以及元空间的关系很像 Java 中接口和类的关系,类实现了接口,这里的类就可以看作是永久代和元空间,接口可以看作是方法区,也就是说永久代以及元空间是 HotSpot 虚拟机对虚拟机规范中方法区的两种实现方式。
并且,永久代是 JDK 1.8 之前的方法区实现,JDK 1.8 及以后方法区的实现变成了元空间。

三者之间的关系
常量池与运行时常量池
常量池是 .class 文件中的静态数据结构,而运行时常量池是常量池在运行时的内存表示。
当类被加载到 JVM 中时,JVM 会将 .class 文件中的常量池信息复制到运行时常量池中,并且对符号引用进行解析和转换。
可以说,运行时常量池是常量池在运行时的具体体现,二者是静态与动态的关系。
运行时常量池与字符串常量池
- 运行时常量池包含了多种类型的常量,而字符串常量池专门用于存储字符串常量。
- 字符串常量池利用运行时常量池的框架,实现了字符串的共享和复用,以节省内存。
- 在JDK 6及之前,字符串常量池是运行时常量池的一部分,而JDK 7及之后字符串常量池被移到堆中,因此字符串常量池不再是严格意义上的运行时常量池的一部分。
- 运行时常量池中存储的是字符串常量的引用,而不是字符串对象本身。字符串对象的实际内容存储在堆中的字符串常量池。
- 例如,当一个类文件中定义了字符串常量 “hello” 时:
- 运行时常量池中会存储一个指向堆中字符串常量池的引用。
- 堆中的字符串常量池会存储实际的 String 对象。
例如:
String str1 = "hello";
String str2 = "hello";
在 JDK 7 及以后,当第一次遇到 “hello” 时,会在堆中的字符串常量池创建 “hello” 字符串对象,运行时常量池记录其引用;
第二次遇到 “hello” 时,发现字符串常量池已有该对象,运行时常量池直接复用这个引用,所以 str1 和 str2 引用的是同一个堆中的字符串对象。
总结
- 常量池是.class文件的一部分(每个class文件都有自己独立的常量池),提供了类或接口在编译时所需的各种常量信息。
- 运行时常量池是JVM方法区中的一部分,当JVM加载一个类文件时,会将该类的常量池信息(常量池表)加载到方法区内的运行时常量池中。
- 字符串常量池特别针对字符串进行了优化设计,以实现字符串共享,减少内存占用。它是一个类似于哈希表(HashTable)的数据结构,在 HotSpot 虚拟机中由 StringTable 类实现。
- JDK 1.7之后运行时常量池在方法区中,字符串常量池在堆中。因此在JDK 6及之前,字符串常量池是运行时常量池的一部分,而JDK 7及之后字符串常量池被移到堆中,因此字符串常量池不再是严格意义上的运行时常量池的一部分。
- 运行时常量池中存储的是字符串常量的引用,而不是字符串对象本身。字符串对象的实际内容存储在堆中的字符串常量池。
相关文章:
JVM中常量池和运行时常量池、字符串常量池三者之间的关系
文章目录 前言常量池(Constant Pool)运行时常量池(Runtime Constant Pool)字符串常量池(String Literal Pool)运行时常量池和字符串常量池位置变化方法区与永久代和元空间的关系三者之间的关系常量池与运行…...
KV 缓存简介
以下是关于 KV缓存(Key-Value Cache) 的简介,涵盖其定义、原理、作用及优化意义: 1. 什么是KV缓存? KV缓存 是Transformer架构(如GPT、LLaMA等大模型)在自回归生成任务(如文本生成&…...
Mysql篇——SQL优化
本篇将带领各位了解一些常见的sql优化方法,学到就是赚到,一起跟着练习吧~ SQL优化 准备工作 准备的话我们肯定是需要一张表的,什么表都可以,这里先给出我的表结构(表名:userinfo) 通过sql查看…...
算法基础 -- ARM 体系架构设计专家的算法提升目标
算法提升目标:ARM 体系架构设计专家 1. 位运算优化 相关 ARM 知识点:SIMD、NEON、SVE、低功耗优化、加密计算、数据压缩 推荐题目: 136. 只出现一次的数字(异或运算)190. 颠倒二进制位(位反转,ARM rbit…...
不同开发语言对字符串的操作
一、字符串的访问 Objective-C: 使用 characterAtIndex: 方法访问字符。 NSString *str "Hello, World!"; unichar character [str characterAtIndex:0]; // 访问第一个字符 H NSLog("%C", character); // 输出: H NSString 内部存储的是 UTF-16 编…...
Oracle Linux Server 7.9安装fail2ban
yum search oracle-epel-release yum install oracle-epel-release-el7 search fail2ban yum install fail2ban nano /etc/fail2ban/jail.d/00-firewalld.conf # defalut这里是设定全局设置,如果下面的监控没有设置就以全局设置的值设置。 [DEFAULT] # 用于指定哪…...
FPGA|Verilog-SPI驱动
最近准备蓝桥杯FPGA的竞赛,因为感觉官方出的IIC的驱动代码思路非常好,写的内容非常有逻辑并且规范。也想学习一下SPI的协议,所以准备自己照着写一下。直到我打开他们给出的SPI底层驱动,我整个人傻眼了,我只能说&#x…...
Windows11 新机开荒(二)电脑优化设置
目录 前言: 一、注册微软账号绑定权益 二、此电脑 桌面图标 三、系统分盘及默认存储位置更改 3.1 系统分盘 3.2 默认存储位置更改 四、精简任务栏 总结: 前言: 本文承接上一篇 新机开荒(一) 上一篇文章地址&…...
关于deepseek R1模型分布式推理效率分析
1、引言 DeepSeek R1 采用了混合专家(Mixture of Experts,MoE)架构,包含多个专家子网络,并通过一个门控机制动态地激活最相关的专家来处理特定的任务 。DeepSeek R1 总共有 6710 亿个参数,但在每个前向传播…...
揭秘大数据 | 9、大数据从何而来?
在科技发展史上,恐怕没有任何一种新生事物深入人心的速度堪比大数据。 如果把2012年作为数据量爆发性增长的第一年,那么短短数年,大数据就红遍街头巷尾——从工业界到商业界、学术界,所有的行业都经受了大数据的洗礼。从技术的迭…...
使用Dependency Walker和Beyond Compare快速排查dll动态库损坏或被篡改的问题
目录 1、问题描述 2、用Dependency Walker工具打开qr.dll库,查看库与库的依赖关系以及接口调用情况,定位问题 3、使用Beyond Compare工具比较一下正常的msvcr100d.dll和问题msvcr100d.dll的差异 4、最后 C软件异常排查从入门到精通系列教程ÿ…...
3.14学习总结 排序算法
插入排序: 1.直接插入排序 维护一个有序区,把元素一个个插入有序区的适当位置,直到所有元素都有序为止。 for (int i 0;i < n - 1;i) {//升序int end i;int temp k[end 1];while (end > 0) {if (temp < k[end]) {k[end 1] …...
Hadoop、Spark、Flink Shuffle对比
一、Hadoop的shuffle 前置知识: Map任务的数量由Hadoop框架自动计算,等于分片数量,等于输入文件总大小 / 分片大小,分片大小为HDFS默认值128M,可调 Reduce任务数由用户在作业提交时通过Job.setNumReduceTasks(int)设…...
本地部署 RAGFlow - 修改默认端口
本地部署 RAGFlow - 修改默认端口 1. 前提条件2. 部署 RAGFlow 1. 前提条件 确保 vm.max_map_count 不小于 262144: 如需确认 vm.max_map_count 的大小: sysctl vm.max_map_count如果 vm.max_map_count 的值小于 262144,可以进行重置&…...
repo init 错误 Permission denied (publickey)
一、已经生成ssh-key并设置到gerrit上 二、已经设置.gitconfig (此步骤是公司要求,设置gerrit地址为一个别名之类的,有的公司不需要) 然后出现下面的错误,最后发现忘记设置git的用户名和邮箱 1. git config --globa…...
Django settings.py 文件全解析
本篇详细介绍 Django settings.py 文件各个配置项的教程,涵盖核心配置项的作用及最佳实践 一、基础配置 1. BASE_DIR BASE_DIR Path(__file__).resolve().parent.parent作用:项目根目录路径,用于构建其他路径(如模板、静态…...
TSB - AD 解读 — 迈向可靠、透明的 TSAD 任务
目录 一 文章动机 二 TSAD 领域内的两类缺陷 三 数据集的构建 四 实验结果及结论 项目宣传链接:TSB-AD 代码链接: TheDatumOrg/TSB-AD: TSB-AD: Towards A Reliable Time-Series Anomaly Detection Benchmark 原作者解读:NeurIPS 2…...
下载 CSS 文件阻塞,会阻塞构建 DOM 树吗?会阻塞页面的显示吗?
下载 CSS 文件会对页面的渲染过程产生影响,具体是否阻塞 DOM 树的构建和页面的显示,取决于浏览器的渲染机制。 1. CSS 文件下载是否会阻塞 DOM 树的构建? 一般情况下,CSS 文件下载不会阻塞 DOM 树的构建: DOM 树的构建…...
6个月的Go语言学习甘特图路线图 从零基础到项目实战
以下是为期6个月的Go语言学习甘特图(2025年4月-2025年10月),包含详细阶段划分、对应资源及项目产出文档说明: #mermaid-svg-yQbkZCpCAXv6iXKC {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fi…...
论文阅读:2023-arxiv Can AI-Generated Text be Reliably Detected?
总目录 大模型安全相关研究:https://blog.csdn.net/WhiffeYF/article/details/142132328 文章目录 Abstract(摘要)1 Introduction(引言)Conclusion(结论) Can AI-Generated Text be Reliably D…...
查看IP地址/Ping 命令
目录 Windows Linux macOS Ping 命令 Windows 使用终端: 按下 Win R 键,打开“运行”对话框,输入 cmd 并按 Enter。 在命令提示符中输入 ipconfig,按 Enter。系统会显示网络适配器的详细信息,包括 IPv4 地址、子…...
Language Models are Few-Shot Learners,GPT-3详细讲解
GPT的训练范式:预训练Fine-Tuning GPT2的训练范式:预训练Prompt predict (zero-shot learning) GPT3的训练范式:预训练Prompt predict (few-shot learning) GPT2的性能太差,新意高&…...
鸿蒙编译框架@ohos/hvigor FileUtil用法
ohos/hvigor FileUtil用法 在鸿蒙(HarmonyOS)开发中,ohos/hvigor 的 FileUtil 是用于文件操作的实用工具类,提供了跨平台的文件读写、路径处理等常用方法。以下是其核心用法和示例: 一、核心方法说明 方法名功能描…...
Hoppscotch 开源API 开发工具
Hoppscotch 是一个开源的 API 开发工具,旨在为开发者提供一个轻量级、快速且功能丰富的 API 开发和调试平台。以下是对其主要特性和功能的详细介绍: 1. 轻量级与高效 Hoppscotch 采用简约的 UI 设计,注重易用性和高效性。它支持实时发送请求…...
Infura 简介
文章目录 Infura 简介Infura 的主要功能Infura 的替代方案(类似服务)AlchemyQuickNodeAnkrMoralisPocket Network 什么时候选择 Infura? Infura 简介 Infura 是一个 区块链基础设施即服务(BaaS, Blockchain as a Service…...
【芯片验证】面试题·对深度为60的数组进行复杂约束的技巧
朋友发给我的芯片验证笔试题,觉得很有意思,和大家分享一下。 面试题目 class A中一个长度为60的随机数组rand int arr[60],如何写约束使得: 1.每个元素的值都在(0,100]之间,且互不相等; 2.最少有三个元素满足勾股数要求,比如数组中包含3,4,5三个点; 请以解约束最快…...
Manus “Less structure,More intelligence ”独行云端处理器
根据市场调研机构Statista数据显示,全球的AR/AR的市场规模预计目前将达到2500亿美元,Manus作为VR手套领域的领军企业,足以颠覆你的认知。本篇文章将带你解读Manus产品,针对用户提出的种种问题,Manus又将如何解决且让使…...
【再读】R1-Onevision通过跨模态形式化为复杂多模态推理任务提供了系统性解决方案
R1-Onevision:跨模态形式化驱动的多模态推理技术突破,R1-Onevision通过跨模态形式化、双阶段训练和教育级基准测试,为多模态推理树立了新标杆。其技术创新不仅提升了模型在复杂任务中的表现,更重要的是为行业提供了一种可解释、可迁移的多模态处理范式。随着形式化方法的不断…...
Mysql-经典实战案例(3): pt-archiver 实现 MySQL 千万级大表分库分表(上)
零基础实战:使用 pt-archiver 实现 MySQL 千万级大表的水平分表(Hash分片) 本文适合人群:MySQL新手、想低成本实践数据库分表的开发者 环境要求:MySQL 5.7、Linux系统(建议CentOS/Ubuntu) 你将学…...
使用JSON存储数据的场景
Json 作为一种通用的数据格式,由于其结构灵活、可拓展等特点,在某些场景下我们也会直接将数据以 Json 格式存储到数据库中。 本文将探讨在开发中使用 JSON 存储数据的常见场景,并通过具体的实例帮助大家更好地理解其应用。 1. 半结构化数据…...
