详解JVM之运行时常量池
作者:flydean 发布时间:2022-08-04 03:41:03
class文件中的常量池
之前我们在讲class文件的结构时,提到了每个class文件都有一个常量池,常量池中存了些什么东西呢?
字符串常量,类和接口名字,字段名,和其他一些在class中引用的常量。
运行时常量池
但是只有class文件中的常量池肯定是不够的,因为我们需要在JVM中运行起来。
这时候就需要一个运行时常量池,为JVM的运行服务。
运行时常量池和class文件的常量池是一一对应的,它就是class文件的常量池来构建的。
运行时常量池中有两种类型,分别是symbolic references符号引用和static constants静态常量。
其中静态常量不需要后续解析,而符号引用需要进一步进行解析处理。
什么是静态常量,什么是符号引用呢? 我们举个直观的例子。
String site="www"
上面的字符串"www.com"可以看做是一个静态常量,因为它是不会变化的,是什么样的就展示什么样的。
而上面的字符串的名字“site”就是符号引用,需要在运行期间进行解析,为什么呢?
因为site的值是可以变化的,我们不能在第一时间确定其真正的值,需要在动态运行中进行解析。
静态常量详解
运行时常量池中的静态常量是从class文件中的constant_pool构建的。可以分为两部分:String常量和数字常量。
String常量
String常量是对String对象的引用,是从class中的CONSTANT_String_info结构体构建的:
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
tag就是结构体的标记,string_index是string在class常量池的index。
string_index对应的class常量池的内容是一个CONSTANT_Utf8_info结构体。
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_Utf8_info是啥呢?它就是要创建的String对象的变种UTF-8编码。
我们知道unicode的范围是从0x0000 至 0x10FFFF。
变种UTF-8就是将unicode进行编码的方式。那是怎么编码呢?
从上图可以看到,不同的unicode范围使用的是不同的编码方式。
注意,如果一个字符占用多个字节,那么在class文件中使用的是 big-endian 大端优先的排列方式。
如果字符范围在FFFF之后,那么使用的是2个3字节的格式的组合。
讲完class文件中CONSTANT_String_info的结构之后,我们再来看看从CONSTANT_String_info创建运行时String常量的规则:
规则一:如果String.intern之前被调用过,并且返回的结果和CONSTANT_String_info中保存的编码是一致的话,表示他们指向的是同一个String的实例。
规则二:如果不同的话,那么会创建一个新的String实例,并将运行时String常量指向该String的实例。最后会在这个String实例上调用String的intern方法。调用intern方法主要是将这个String实例加入字符串常量池。
数字常量
数字常量是从class文件中的CONSTANT_Integer_info, CONSTANT_Float_info, CONSTANT_Long_info和 CONSTANT_Double_info 构建的。
符号引用详解
符号引用也是从class中的constant_pool中构建的。
对class和interface的符号引用来自于CONSTANT_Class_info。
对class和interface中字段的引用来自于CONSTANT_Fieldref_info。
class中方法的引用来自于CONSTANT_Methodref_info。
interface中方法的引用来自于CONSTANT_InterfaceMethodref_info。
对方法句柄的引用来自于CONSTANT_MethodHandle_info。
对方法类型的引用来自于CONSTANT_MethodType_info。
对动态计算常量的符号引用来自于CONSTANT_MethodType_info。
对动态计算的call site的引用来自于CONSTANT_InvokeDynamic_info。
String Pool字符串常量池
我们在讲到运行时常量池的时候,有提到String常量是对String对象的引用。那么这些创建的String对象是放在什么地方呢?
没错,就是String Pool字符串常量池。
这个String Pool在每个JVM中都只会维护一份。是所有的类共享的。
String Pool是在1.6之前是存放在方法区的。在1.8之后被放到了java heap中。
注意,String Pool中存放的是字符串的实例,也就是用双引号引起来的字符串。
那么问题来了?
String name = new String("www");
到底创建了多少个对象呢?
来源:https://www.cnblogs.com/flydean/p/jvm-run-time-constant-pool.html


猜你喜欢
- 发送邮件在web开发中,发送邮件是一个很常用的功能,Spring Boot也集成了发送邮件的功能基本使用使用Spring Boot的发送邮件
- 一、包含与删除两种方法解析1.boolean contains(Object o);判断集合中是否包含某个元素。package com.bj
- 实现GridView的横向滚动效果如下图:具体实现的代码•1. 主界面布局代码:activity_main.xml<?xml vers
- application.ymlspring: datasource: username: root password
- forward_list 概述forward_list 是 C++ 11 新增的容器,它的实现为单链表。forward_list 是支持从容
- 在客户端中,为了防止界面假死状态,或者不能拖动界面,可以使用BackgroundWorker。1.在界面上拖动一个BackgroundWor
- 一、循环语句的几种语法语法:for循环格式:for(初始化语句;条件判断;递进语句){循环体;}while循环格式:初始化语句;while(
- 目录前言一、内存优化策略二、具体优化的点1.避免内存泄漏2.Bitmap等大对象的优化策略(1) 优化Bitmap分辨率(2) 优化单个像素
- 本文采用半译方式。在本文中,将会介绍 C# 7.2 中引入的新类型:Span 和 Memory,文章深入研究 Span<T&
- * String类是不可变类,只要对String进行修改,都会导致新的对象生成。* StringBuffer和StringBuilder都是
- HTTP请求,在日常开发中,还是比较常见的,今天给大家分享HttpUtils如何使用。阅读本文,你将收获:简单总结HTTP请求常用配置;Ja
- 不同点:不能直接实例化接口。接口不包含方法的实现。接口可以多继承,类只能单继承。类定义可以在不同的源文件之间进行拆分。相同点:接口、类和结构
- 前言 之前的文章有介绍ActivityGroup,不少人问嵌套使用的问题,同样的需求在Fragment中也存在,幸好在最新的An
- 1、什么是ThreadLocal变量ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thr
- 一.EventBus概述 1.EventBus的三要素EventBus有三个主要的元素需要我们先了解一下:Event:事件,可以是任意类型的
- 如下:public static void CreateConfig(){ //c#可以添加内置的app.conf
- fatal error C1003: error count exceeds number; stopping compilation中文对
- 本文实例讲述了java基于AES对称加密算法实现的加密与解密功能。分享给大家供大家参考,具体如下:package com.soufun.co
- 本文实例分析了C#遍历List并删除某个元素的方法。分享给大家供大家参考。具体如下:1、我们选择用for循环:for(int i=0;i&l
- 目录1.问题引出2.解决办法3.另外一种自定义序列化机制(介绍Externalizable)1.问题引出在某些情况下,我们可能不想对于一个对