持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第25天,点击查看活动详情
运行时常量池 VS 常量池
官方文档:docs.oracle.com/javase/spec…
后面会细讲常量池,这里为了讲清楚方法区,简单带一下。
- 方法区,内部包含了运行时常量池
- 字节码文件,内部包含了常量池。(之前的字节码文件中已经看到了很多Constant pool的东西,这个就是常量池)
- 要弄清楚方法区,需要理解清楚ClassFile,因为加载类的信息都在方法区。
- 要弄清楚方法区的运行时常量池,需要理解清楚ClassFile中的常量池。
常量池
- 一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述符信息外。还包含一项信息就是常量池表(Constant Pool Table),包括各种字面量和对类型、域和方法的符号引用。
- 字面量: 10 , “我是某某”这种数字和字符串都是字面量
为什么需要常量池?
- 一个java源文件中的类、接口,编译后产生一个字节码文件。而Java中的字节码需要数据支持,通常这种数据会很大以至于不能直接存到字节码里,换另一种方式,可以存到常量池。这个字节码包含了指向常量池的引用。在动态链接的时候会用到运行时常量池,之前有介绍
比如:如下的代码:
public class SimpleClass {
public void sayHello() {
System.out.println("hello");
}
}
- 虽然上述代码只有194字节,但是里面却使用了String、System、PrintStream及Object等结构。
- 比如说我们这个文件中有6个地方用到了”hello”这个字符串,如果不用常量池,就需要在6个地方全写一遍,造成臃肿。我们可以将”hello”等所需用到的结构信息记录在常量池中,并通过引用的方式,来加载、调用所需的结构
- 这里的代码量其实很少了,如果代码多的话,引用的结构将会更多,这里就需要用到常量池了。
常量池中有啥?
- 数量值
- 字符串值
- 类引用
- 字段引用
- 方法引用
MethodInnerStrucTest 的 test1方法的字节码
1、#3,#5等等这些带# 的,都是引用了常量池。
常量池总结
常量池、可以看做是一张表,虚拟机指令根据这张常量表找到要执行的类名、方法名、参数类型、字面量等类型。
运行时常量池
- 运行时常量池(Runtime Constant Pool)是方法区的一部分。
- 常量池表(Constant Pool Table)是Class字节码文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。(运行时常量池就是常量池在程序运行时的称呼)
- 运行时常量池,在加载类和接口到虚拟机后,就会创建对应的运行时常量池。
- JVM为每个已加载的类型(类或接口)都维护一个常量池。池中的数据项像数组项一样,是通过索引访问的。
- 运行时常量池中包含多种不同的常量,包括编译期就已经明确的数值字面量,也包括到运行期解析后才能够获得的方法或者字段引用。此时不再是常量池中的符号地址了,这里换为真实地址。
- 运行时常量池,相对于Class文件常量池的另一重要特征是:具备动态性。
- 运行时常量池类似于传统编程语言中的符号表(symbol table),但是它所包含的数据却比符号表要更加丰富一些。
- 当创建类或接口的运行时常量池时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大值,则JVM会抛OutofMemoryError异常。