面试题系列第5篇:JDK的运行时常量池、字符串常量池、静态常量池,还傻傻分不清?

2023-10-24 01:20

本文主要是介绍面试题系列第5篇:JDK的运行时常量池、字符串常量池、静态常量池,还傻傻分不清?,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《Java面试题系列》:一个长知识又很有意思的专栏。深入挖掘、分析源码、汇总原理、图文结合,打造公众号系列文章,面试与否均可提升Level。欢迎持续关注【程序新视界】。本篇为第5篇。

【番外篇】本篇核心:JDK各个版本中JDK的运行时常量池、字符串常量池、静态常量池的功能及存储位置。

在写本系列文章时,发现一旦追究起底层实现都会涉及到一些内存结构的问题。其中涉及比较多的便是常量池,本篇文章汇总一下JDK的运行时常量池、字符串常量池、静态常量池的功能及存储结构。

JVM运行时内存结构

在了解常量池之前我们先通过一张图了解一下JVM的整个内存分布图。下图为JDK7的内存结构:
在这里插入图片描述

在上图中JVM所管理的内存主要包括以下区域:程序计数器(Program Counter Register)、虚拟机栈(VM Stack)、本地方法栈(Native Method Stack)、方法区(Method Area)、堆(Heap)。

不同版本的JVM的内存结构有不同的变化,这些变化对我们今天要讲的三个概念会有所影响,后面我们会逐一讲解。

了解了JVM内存结构,那么运行时常量池、字符串常量池、静态常量池对于的都位于JVM的什么区域呢?先来看看它们的定义及功能。

静态常量池

Java程序要运行时,需要编译器先将源代码文件编译成字节码(.class)文件,然后在由JVM解释执行。

class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant pool table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入运行时常量池中存放。

静态常量池就是上面说的class文件中的常量池。class常量池是在编译时每个class文件中都存在。不同的符号信息放置在不同标志的常量表中。
在这里插入图片描述

常量池中存放的符号信息,在JVM执行指令时需要依赖使用。常量池中的所有项都具有如下通用格式:

cp_info {u1 tag;     //表示cp_info的单字节标记位u1 info[];  //两个或更多的字节表示这个常量的信息,信息格式由tag的值确定
}

支持的类型信息如下:
在这里插入图片描述

以CONSTANT_Class为例,它用于表示类或者接口,格式如下:

CONSTANT_Class_info {u1 tag;       //这个值为CONSTANT_Class (7)u2 name_index;//一个index,表示一个索引,引用的是CONSTANT_UTF8_info
}

CONSTANT_Class_info类型是由一个tag和一个name_index组成。name_index中的index表示它是一个索引,引用的是CONSTANT_UTF8_info。

CONSTANT_Utf8_info用于表示字符常量的值,结构如下所示:

CONSTANT_Utf8_info {u1 tag;u2 length;u1 bytes[length];
}

tag表示为:CONSTANT_Utf8(1);length指明了bytes[]数组的长度;bytes[]数组引用了上一个length作为其长度。字符常量采用改进过的UTF-8编码表示。

对于静态常量池我们需要知道它存在于编译器,如果说与运行时有关的话,可以说运行时中的常量是JVM加载class文件之后进行分配的。

运行时常量池

运行时常量池就是将编译后的类信息放入方法区中,也就是说它是方法区的一部分。

运行时常量池用来动态获取类信息,包括:class文件元信息描述、编译后的代码数据、引用类型数据、类文件常量池等。

运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中。每个class都有一个运行时常量池,类在解析之后将符号引用替换成直接引用,与全局常量池中的引用值保持一致。

运行时常量池相对于class文件常量池的另外一个特性是具备动态性,java语言并不要求常量一定只有编译器才产生,也就是并非预置入class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中。

字符串常量池

字符串池里的内容是在类加载完成,经过验证、准备阶段之后存放在字符串常量池中。关于字符串常量池的具体实现我们这里先不展开,后面用专门的文章来进行讲解。

字符串常量池的处理机制我们前面文章已经讲到,只会存储一份,被所有的类共享。基本流程是:创建字符串之前检查常量池中是否存在,如果存在则获取其引用,如果不存在则创建并存入,返回新对象引用。

字符串常量池随着JDK版本的演化所在的位置也在不断的变化,下面我们会专门用图讲解一下。

常量池内存位置演化

在JDK1.7之前运行时常量池逻辑包含字符串常量池存放在方法区, 此时hotspot虚拟机对方法区的实现为永久代。
在这里插入图片描述

在JDK1.7字符串常量池和静态变量被从方法区拿到了堆中,运行时常量池剩下的还在方法区, 也就是hotspot中的永久代。
在这里插入图片描述

在JDK8 hotspot移除了永久代用元空间(Metaspace)取而代之, 这时候字符串常量池还在堆,运行时常量池还在方法区,只不过方法区的实现从永久代变成了元空间(Metaspace)
在这里插入图片描述

通过上面的图解,我们可以轻易得知在不同的版本中方法区及内部组成部分是在不断变化的。

小结

通过本篇文章我们针对JDK的运行时常量池、字符串常量池、静态常量池进行逐一讲解,同时针对不同版本的JVM(hotspot虚拟机)中它们所处的内存位置进行了图解。

总结一下就是:静态变量处于编译器,存在于class文件内,可通过javap verbose命令查看字符串合并时查看的是静态常量池里面的内容;字符串常量池曾经属于运行时常量池的一部分,位于方法区,但随着JVM版本的演变,二者已经分开。在JDK8以后字符串常量池位于堆中,而运行时常量池位于方法区。

其实关于此部分的内容还有很多,特别是字符串常量池,欢迎大家持续关注。后续会对字符串常量池再进行针对性的分析。在此过程中也发现很多文章在没有指定JDK版本的情况下进行描述,都有失偏驳。本系列为大家考证,去伪存真。

原文链接:《面试题系列第5篇:JDK的运行时常量池、字符串常量池、静态常量池,还傻傻分不清?》

参考文章:

https://blog.csdn.net/qq_31615049/article/details/81611918

https://blog.csdn.net/weixin_43232955/article/details/107411378


程序新视界

公众号“ 程序新视界”,一个让你软实力、硬技术同步提升的平台,提供海量资料

微信公众号:程序新视界

这篇关于面试题系列第5篇:JDK的运行时常量池、字符串常量池、静态常量池,还傻傻分不清?的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/271760

相关文章

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Python 常用数据类型详解之字符串、列表、字典操作方法

《Python常用数据类型详解之字符串、列表、字典操作方法》在Python中,字符串、列表和字典是最常用的数据类型,它们在数据处理、程序设计和算法实现中扮演着重要角色,接下来通过本文给大家介绍这三种... 目录一、字符串(String)(一)创建字符串(二)字符串操作1. 字符串连接2. 字符串重复3. 字

Java JDK Validation 注解解析与使用方法验证

《JavaJDKValidation注解解析与使用方法验证》JakartaValidation提供了一种声明式、标准化的方式来验证Java对象,与框架无关,可以方便地集成到各种Java应用中,... 目录核心概念1. 主要注解基本约束注解其他常用注解2. 核心接口使用方法1. 基本使用添加依赖 (Maven

Java 字符串操作之contains 和 substring 方法最佳实践与常见问题

《Java字符串操作之contains和substring方法最佳实践与常见问题》本文给大家详细介绍Java字符串操作之contains和substring方法最佳实践与常见问题,本文结合实例... 目录一、contains 方法详解1. 方法定义与语法2. 底层实现原理3. 使用示例4. 注意事项二、su

SpringBoot中@Value注入静态变量方式

《SpringBoot中@Value注入静态变量方式》SpringBoot中静态变量无法直接用@Value注入,需通过setter方法,@Value(${})从属性文件获取值,@Value(#{})用... 目录项目场景解决方案注解说明1、@Value("${}")使用示例2、@Value("#{}"php

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Python 字符串裁切与提取全面且实用的解决方案

《Python字符串裁切与提取全面且实用的解决方案》本文梳理了Python字符串处理方法,涵盖基础切片、split/partition分割、正则匹配及结构化数据解析(如BeautifulSoup、j... 目录python 字符串裁切与提取的完整指南 基础切片方法1. 使用切片操作符[start:end]2

MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)

《MyBatis的xml中字符串类型判空与非字符串类型判空处理方式(最新整理)》本文给大家介绍MyBatis的xml中字符串类型判空与非字符串类型判空处理方式,本文给大家介绍的非常详细,对大家的学习或... 目录完整 Hutool 写法版本对比优化为什么status变成Long?为什么 price 没事?怎