java运行时数据区分析
概览
堆
是Java虚拟机所管理的内存中最大的一块。由所有线程共享,在虚拟机启动时创建。
堆区唯一目的就是存放对象实例。
堆中可细分为新生代和老生代(垃圾回收期主要回收的区域),新生代又可细分为Eden空间,From Survivor空间、To Survivor空间。
方法区
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
全局字符串池
全局字符串池里的内容是在类加载完成,经过验证,准备阶段之后在堆中生成字符串对象实例,然后将该字符串对象实例的引用值存到string pool中(记住:string pool中存的是引用值而不是具体的实例对象,具体的实例对象是在堆中开辟的一块空间存放的。)。 在HotSpot VM里实现的string pool功能的是一个StringTable类,它是一个哈希表,里面存的是驻留字符串(也就是我们常说的用双引号括起来的)的引用(而不是驻留字符串实例本身),也就是说在堆中的某些字符串实例被这个StringTable引用之后就等同被赋予了”驻留字符串”的身份。这个StringTable在每个HotSpot VM的实例只有一份,被所有的类共享。
Class文件常量池
class文件除了包含类的版本、字段、方法、接口等描述信息外,还有一项信息就是常量池(constant pool table),用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)。
字面量就是常量的概念,如文本字符串、被声明为final的常量值的。
符号引用是一组符号来描述所引用的目标,符号引用可以是任何形式的字面量。
常量池的每一项常量都是一个表,一共有如下表所示的11种各不相同的表结构数据,这每个表开始的第一位都是一个字节的标志位
运行时常量池
jvm在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。在上面我也说了,class常量池中存的是字面量和符号引用,也就是说他们存的并不是对象的实例,而是对象的符号引用值。而经过解析(resolve)之后,也就是把符号引用替换为直接引用,解析的过程会去查询全局字符串池,也就是我们上面所说的StringTable,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的。
总结
- 全局常量池在每个JVM中只有一份,存放的是字符串常量的引用值
- class常量池是在编译的时候每个class都有的在编译阶段,存放的是常量的符号引用
- 运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致
Java虚拟机栈
描述Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。一个方法对应一个栈帧。
局部变量表存放了各种基本类型,对象引用和returnAddress类型(指向一条字节码指令地址)。其中64位长度long 和 double占两个局部变量空间,其他只占一个。
public int myCalculate() {
int a = 1;
int b = 2;
int c = 3;
int d = 4;
int result = (a + b - c) * d;
return result;
}
局部变量表
操作数栈
本地方法栈
和java虚拟机栈类似,不同的是其为Native方法服务
程序计数器
是当前线程所执行的字节码的行号指示器,每个线程都有一个独立的程序计数器。
参考博客
字符串常量池、class常量池和运行时常量池:https://blog.csdn.net/qq_26222859/article/details/73135660