搜索
写经验 领红包

jvm常量池(jvm中常量池在方法区还是堆中)

导语:JVM中"常量池"和"符号引用"的具体说明

符号引用是JVM在编译之后用于描述类,方法,接口等信息的标识符,在常量池,类加载过程的相关介绍中出现的次数很多,但是虽然看了很多次但还是感觉很抽象,所以做个总结尽量把抽象的&34;说具体。

说符号引用之前先具体的介绍一下class文件中的常量池,虽然在文章《JVM类加载流程及常量池介绍》中已经给过常量持的介绍了,但是不够具体,现在常量池重新介绍:

class文件中常量池中的数据的数据结构如下:

cp_info {    u1 tag;    u1 info[];}

tag中的每一个值表示一种常量类型,所有的类型及其代表的值如下表。

info数组中的值代表着这个类中该常量类型的描述,每种类型的描述结构不一样,下边会介绍类和方法的描述结构。

接下来结合字节码文件举例说明:

一个类A在加载的时候,类A中可能持有其它类B的引用,这是很常见的编码方式。此时B没有加载,但是JVM必须知道有B这么一个类存在,也就是JVM要描述一个在运行时数据区域不存在的类。所以JVM就要自己给它做个描述。除了类之外,具有符号引用的还有接口,字段,类方法,接口方法,方法类型和句柄,呼叫站点说明符解析。我们以类和方法的符号引用,结合字节码举例说明:

类的符号引用格式如下:

CONSTANT_Class_info {    u1 tag;     u2 name_index;}

tag是JVM规定的类符号引用的固定数值7;name_index是class文件中常量池中有效的索引;u1,u2,分别这代表数字的长度,u1一个字节,u2两个字节。并且索引地址的数据类型必须是CONSTANT_Utf8_info结构的(这是JVM规定的),为了避免文章摊大饼,CONSTANT_Utf8_info的结构不在给出,可以把它理解成一个utf-8编码的字符串,注意不是java里的字符串对象,字符串对象在CONSTANT_String_info。

如上图就是一个类的字符串常量的字节码,它使用javac编译再用javap反编译的。不涉及到任何运行时的内存布局。查看20表示常量池中的一个索引,这个索引上文已经提到过是个utf8类型的字符串,找到20索引处的位置,果然存放的是字符串”Test11“,至此,java在常量池中已经描述完成了一个类。

接下来继续看方法的符号索引的格式:

CONSTANT_Methodref_info {    u1 tag;    u2 class_index;    u2 name_and_type_index;}

tag依然代表标识方法引用类型的数值10,长度是一个字节;class_index代表的是常量池中的索引地址,该处索引位置的类型必须是class类型的,两个字节长度;name_and_type_index也是常量池中的位置索引,索引位置的常量类型必须是CONSTANT_NameAndType_info类型的,该类型描述的是一个字段或者方法。结构如下:

CONSTANT_NameAndType_info {    u1 tag;    u2 name_index;    u2 descriptor_index;}

tag不说了,name_index也是常量池的索引,索引位置的类型是必须是CONSTANT_Utf8_info,也就是说一个字符串,描述的特殊方法名称 <init>或表示字段或方法的有效非限定名称。descriptor_index索引地址类型也是CONSTANT_Utf8_info,它描述的是有效字段的描述符和方法描述符,继续集合字节码查看。

3和3位置正好是一个类并且19位置又指向了两个索引5。分别对应CONSTANT_NameAndType_info结构中的name_index,descriptor_index。5位置的字符串()V是一个方法的描述符,一个方法描述符包含零个或多个参数描述符,表示该方法采用的参数类型,以及一个返回描述符,表示该方法返回的值(如果有)的类型。()V表示无参,返回值是void。

通过和字节码文件的结合讲解符号引用,就会清楚很多,我们只是讲解了两种符号引用。感兴趣的同学可以自行去解析其它类型的索引。

从上边的讲解和截图中我们也知道了class文件中常量池的构成:字面量和符号引用。符号引用不说了,上边的讲解中出现的元素都是符号引用,那字面量是什么呢?看下边的截图:

字符串和倍final修饰的常量的值都会存储到常量池中,这些就是字面量。

本文内容由小余整理编辑!