class常量池、运行时常量池和字符串常量池的关系
类常量池、运行时常量池和字符串常量池这三种常量池,在Java中扮演着不同但又相互关联的角色。理解它们之间的关系,有助于深入理解Java虚拟机(JVM)的内部工作机制,尤其是在类加载、内存分配和字符串处理方面。
类常量池(Class Constant Pool)
每个Java类文件(.class文件)都具有自己的类常量池,它用于存储编译期生成的常量,包括各种字面量(字面量就是指由字母、数字等构成的字符串或者数值)和符号引用(比如类和接口的全名、字段的名称和描述符、方法的名称和描述符)。类常量池在编译期间就已经被确定,并被保存在.class文件中。
Class常量池是用来保存常量的一个中间场所。在JVM真的运行时,需要把类常量池中的常量加载到内存中的运行时常量池中。
运行时常量池(Runtime Constant Pool)
运行时常量池是类被加载到JVM时类常量池的内存版本:当Java类被加载到JVM时,各个类文件中的类常量池内容被读取并存入到运行时常量池中,其中字符串的部分直接进到字符串池,其他常量进入到运行时常量池。
根据Java虚拟机规范约定:每一个运行时常量池都在Java虚拟机的方法区中分配,在加载类和接口到虚拟机后,就创建对应的运行时常量池。
规范中规定了运行时常量池属于方法区,但是没规定方法区属于哪。于是虚拟机在各自实现的时候就各显神通了。在不同版本的JDK中,运行时常量池所处的位置也不一样。以HotSpot虚拟机为例:
在JDK 1.7之前,方法区位于永久代,运行时常量池作为方法区的一部分,处于永久代中,字符串常量池位于运行时常量池的一部分也处于永久代中。

因为使用永久代实现方法区可能导致内存泄露问题,所以,从JDK1.7开始,JVM尝试解决这一问题。
在JDK 1.7中,静态变量和运行时常量池中的字符串常量池转移到了堆内存中,其他类型的常量还保留在方法区中。

在JDK 1.8中,彻底移除了永久代,方法区通过元空间的方式实现,元空间是使用本地内存(Native Memory)来存储类的元数据信息的。随之,运行时常量池也在元空间中实现。

运行时常量池中包含了若干种不同的常量,他的来源主要有两种:
-
编译期可知的字面量和符号引用(来自Class常量池)
-
运行期解析后可获得的常量(如String的intern方法)
字符串常量池(String Constant Pool)
字符串常量池专门用于存储字符串常量。对于 Hotspot 虚拟机来说,类加载时,字符串字面量作为类常量池的一部分信息被载入运行时常量池中,它们以特殊的形式存储在运行时常量池中,此时它们并未被实例化为Java堆中的String对象。只有当这个字符串字面量被调用时,才会对其进行解析,即检查字符串常量池中是否已经存在相同内容的字符串对象。如果存在,就直接返回指向该对象的引用,如果不存在,虚拟机会在字符串常量池中创建一个对应的String实例,并返回这个新实例的引用。
这种处理方式的优势在于,可以减少在类加载阶段对内存的需求和降低开销,因为不是所有的字符串字面量在类的使用周期内都会被用到。同时,此方法延迟了String对象的实例化,直到它们真正被需要,这有助于提高性能并减少内存的无谓占用。
为什么从JDK 1.7开始,字符串常量池从永久代中挪到堆(Heap)中?
主要原因是因为永久代的 GC 回收效率太低,只有在FulIGC的时候才会被执行回收。但是Java中往往会有很多字符串的生命周期都很短暂,将字符串常量池放到堆中,能够更高效及时地回收字符串内存。
字符串常量池中的常量有以下几个来源:
1、字面量常量。
在代码中直接使用双引号括起来的字符串字面值(如 strings="hello”)会被认为是常量,并且会在编译后进入class文件的常量池,并且在运行阶段,进入字符串常量池。这是最常见的字符串常量来源。
2、intern()方法
String类提供了一个intern方法,用于将字符串对象手动添加到字符串常量池中。调用intern()方法时,如果字符串常量池中已经存在相同内容的字符串,将会返回常量池中的引用;如果不存在,则会在常量池中添加该字符串在堆中的引用。
以下有几个非常值得我们注意的地方:
(1)字符串常量池是一个固定大小的Hashtable,默认值大小长度是1009,如果放进字符串常量池的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找,以此判断字符串常量在不在字符串常量池中)。在jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。在jdk7中,StringTable的长度可以通过一个参数指定:
-XX:StringTableSize=99991
(2)对于字符串的拼接,纯字面量和字面量的拼接,会把拼接结果作为常量保存到字符串池。如果在字符串拼接中,有一个参数是非字面量,而是一个变量的话,整个拼接操作会被编译成StringBuilder.append,这种情况编译器是无法知道其确定值的。只有在运行期才能确定。
比如这段代码:
string s1 = "Hollis";
string s2 = "Chuang";
string s3 = s1 + s2;
string s4 = "Hollis" + "Chuang";
在经过反编译后得到代码如下:
String s1 = "Hollis";
string s2 = "chuang" ;
string s3 = (new stringBuilder() ).append(s1).append(s2).toString( );
String s4 = "Hollischuang";
(3)jdk7版本在修改了常量池的基础上,也对intern函数做了修改:
在jdk7之前,字符串常量池位于永久代中,使用intern函数,如果字符串常量池中没有该字符串对象,会在字符串常量池中创建一个该对象,但是在jdk7及之后,字符串常量池移到了堆中,使用intern函数,如果字符串常量池中没有该字符串对象,则不会在字符串常量池中创建对象,而是保存堆中该对象的引用。 比如:
String s = new String("hello") + new String("world");
s.intern();
在第一句代码中,我们创建了一个引用变量s,其指向堆中字符串对象"helloworld",而后调用intern函数,此时字符串常量池中没有"helloworld"字符串对象,如果是在jdk7之前,jvm会在位于永久代的字符串常量池中创建一个"helloworld"字符串对象,但是jdk7之后,字符串常量池位于堆中,不再需要重新创建字符对象,而是在字符串常量池中保存堆中"helloworld"对象的引用。
关于intern函数可以学习这篇文章,讲解非常通透:深入解析String#intern
相关文章:
class常量池、运行时常量池和字符串常量池的关系
类常量池、运行时常量池和字符串常量池这三种常量池,在Java中扮演着不同但又相互关联的角色。理解它们之间的关系,有助于深入理解Java虚拟机(JVM)的内部工作机制,尤其是在类加载、内存分配和字符串处理方面。 类常量池…...
Java | Leetcode Java题解之第88题合并两个有序数组
题目: 题解: class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {int p1 m - 1, p2 n - 1;int tail m n - 1;int cur;while (p1 > 0 || p2 > 0) {if (p1 -1) {cur nums2[p2--];} else if (p2 -1) {cur nums1[p…...
韵搜坊(全栈)-- 前后端初始化
文章目录 前端初始化后端初始化 前端初始化 使用ant design of vue 组件库 官网快速上手:https://www.antdv.com/docs/vue/getting-started-cn 安装脚手架工具 进入cmd $ npm install -g vue/cli # OR $ yarn global add vue/cli创建一个项目 $ vue create ant…...
Android:资源的管理,Glide图片加载框架的使用
目录 一,Android资源分类 1.使用res目录下的资源 res目录下资源的使用: 2.使用assets目录下的资源 assets目录下的资源的使用: 二,glide图片加载框架 1.glide简介 2.下载和设置 3.基本用法 4.占位符(Placehold…...
conll-2012-formatted-ontonotes-5.0中文数据格式说明
CoNLL-2012 数据格式是用于自然语言处理任务的一种常见格式,特别是在命名实体识别、词性标注、句法分析和语义角色标注等领域。这种格式在 CoNLL-2012 共享任务中被广泛使用,该任务主要集中在语义角色标注上。 CoNLL-2012 数据格式通常包括多列…...
SpringBoot集成Seata分布式事务OpenFeign远程调用
Docker Desktop 安装Seata Server seata 本质上是一个服务,用docker安装更方便,配置默认:file docker run -d --name seata-server -p 8091:8091 -p 7091:7091 seataio/seata-server:2.0.0与SpringBoot集成 表结构 项目目录 dynamic和dyna…...
视觉检测系统,是否所有产品都可以进行视觉检测?
视觉检测系统作为一种先进的质检工具,虽然具有广泛的应用范围,但并非所有产品都适合进行视觉检测。本文将探讨视觉检测系统的适用范围及其局限性。 随着机器视觉技术的快速发展,视觉检测系统已广泛应用于各个行业,为产品质检提供…...
通过金山和微软虚拟打印机转换PDF文件,流程方法及优劣对比
文章目录 一、WPS/金山 PDF虚拟打印机1、常规流程2、PDF文件位置3、严重缺陷二、微软虚拟打印机Microsoft Print to Pdf1、安装流程2、微软虚拟打印机的优势一、WPS/金山 PDF虚拟打印机 1、常规流程 安装过WPS办公组件或金山PDF独立版的电脑,会有一个或两个WPS/金山 PDF虚拟…...
采用java+B/S开发的全套医院绩效考核系统源码springboot+mybaits 医院绩效考核系统优势
采用java开发的全套医院绩效考核系统源码springbootmybaits 医院绩效考核系统优势 医院绩效管理系统解决方案紧扣新医改形势下医院绩效管理的要求,以“工作量为基础的考核方案”为核心思想,结合患者满意度、服务质量、技术难度、工作效率、医德医风等管…...
驱动开发-用户空间和内核空间数据传输
1.用户空间-->内核空间(写) #include<linux/uaccess.h> int copy_from_user(void *to,const void __user volatile*from,unsigned long n) 函数功能:将用户空间数据拷贝到内核空间 参数: to:内核空间首地…...
【408精华知识】速看!各种排序的大总结!
文章目录 一、插入排序(一)直接插入排序(二)折半插入排序(三)希尔排序 二、交换排序(一)冒泡排序(二)快速排序 三、选择排序(一)简单选…...
【STM32 |程序实例】按键控制、光敏传感器控制蜂鸣器
目录 前言 按键控制LED 光敏传感器控制蜂鸣器 前言 上拉输入:若GPIO引脚配置为上拉输入模式,在默认情况下(GPIO引脚无输入),读取的GPIO引脚数据为1,即高电平。 下拉输入:若GPIO引脚配置为下…...
Spring boot使用websocket实现在线聊天
maven依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spr…...
品牌设计理念和logo设计方法
一 品牌设计的目的 设计是为了传播,让传播速度更快,传播效率更高,减少宣传成本 二 什么是好的品牌设计 好的设计是为了让消费者更容易看懂、记住的设计, 从而辅助传播, 即 看得懂、记得住。 1 看得懂 就是让别人看懂…...
Python | Leetcode Python题解之第88题合并两个有序数组
题目: 题解: class Solution:def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:"""Do not return anything, modify nums1 in-place instead."""p1, p2 m - 1, n - 1tail m n - 1whi…...
vscode新版本remotessh服务端报`GLIBC_2.28‘ not found解决方案
问题现象 通过vscode的remotessh插件连接老版本服务器(如RHEL7,Centos7)时,插件会报错,无法连接。 查看插件的错误日志可以看到类似如下的报错信息: dc96b837cf6bb4af9cd736aa3af08cf8279f7685/node: /li…...
盘他系列——oj!!!
1.Openjudge 网站: OpenJudge 2.洛谷 网站: 首页 - 洛谷 | 计算机科学教育新生态 3.环球OJ 网站: QOJ - QOJ.ac 4. 北京大学 OJ:Welcome To PKU JudgeOnline 5.自由OJ 网站: https://loj.ac/ 6.炼码 网站:LintCode 炼码 8.力扣 网站: 力扣 9.晴练网首页 - 晴练网...
洛谷 P2657 [SCOI2009] windy 数 题解 数位dp
[SCOI2009] windy 数 题目背景 windy 定义了一种 windy 数。 题目描述 不含前导零且相邻两个数字之差至少为 2 2 2 的正整数被称为 windy 数。windy 想知道,在 a a a 和 b b b 之间,包括 a a a 和 b b b ,总共有多少个 windy 数&…...
Python爬虫入门:网络世界的宝藏猎人
今天阿佑将带你踏上Python的肩膀,成为一名网络世界的宝藏猎人! 文章目录 1. 引言1.1 简述Python在爬虫领域的地位1.2 阐明学习网络基础对爬虫的重要性 2. 背景介绍2.1 Python语言的流行与适用场景2.2 网络通信基础概念及其在数据抓取中的角色 3. Python基…...
【NodeMCU实时天气时钟温湿度项目 6】解析天气信息JSON数据并显示在 TFT 屏幕上(心知天气版)
今天是第六专题,主要内容是:导入ArduinoJson功能库,借助该库解析从【心知天气】官网返回的JSON数据,并显示在 TFT 屏幕上。 如您需要了解其它专题的内容,请点击下面的链接。 第一专题内容,请参考&a…...
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...
LangChain 中的文档加载器(Loader)与文本切分器(Splitter)详解《二》
🧠 LangChain 中 TextSplitter 的使用详解:从基础到进阶(附代码) 一、前言 在处理大规模文本数据时,特别是在构建知识库或进行大模型训练与推理时,文本切分(Text Splitting) 是一个…...
leetcode73-矩阵置零
leetcode 73 思路 记录 0 元素的位置:遍历整个矩阵,找出所有值为 0 的元素,并将它们的坐标记录在数组zeroPosition中置零操作:遍历记录的所有 0 元素位置,将每个位置对应的行和列的所有元素置为 0 具体步骤 初始化…...
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法
用神经网络读懂你的“心情”:揭秘情绪识别系统背后的AI魔法 大家好,我是Echo_Wish。最近刷短视频、看直播,有没有发现,越来越多的应用都开始“懂你”了——它们能感知你的情绪,推荐更合适的内容,甚至帮客服识别用户情绪,提升服务体验。这背后,神经网络在悄悄发力,撑起…...
PostgreSQL 与 SQL 基础:为 Fast API 打下数据基础
在构建任何动态、数据驱动的Web API时,一个稳定高效的数据存储方案是不可或缺的。对于使用Python FastAPI的开发者来说,深入理解关系型数据库的工作原理、掌握SQL这门与数据库“对话”的语言,以及学会如何在Python中操作数据库,是…...
