JVM的内存模型主要有:程序计数器,本地方法栈,JVM栈,堆,方法区
线程独有的:程序计数器,本地方法栈,JVM栈
线程共享的:堆,方法区
程序计数器:用来记录当前线程执行的字节码的行号
本地方法栈:执行本地方法使用的
JVM栈:执行JAVA方法使用。每次调用一个方法时,都为调用的方法创建一个栈帧,放入JVM栈中。
栈帧:里面有局部变量表,操作数栈,动态连接,方法出口等信息。
局部变量表:存储方法参数和定义的局部变量。以slot为单位,具体slot多大,以JVM为准
操作数栈:这个用来对局部变量表中的变量进行加减乘除运算的。因为JVM所有操作都要在栈中运算,而非寄存器中,所以需要这个操作数栈
动态连接:就是用来指向方法区里的对应的字节码的方法位置
方法出口:这个更简单,就是上层方法的位置。当然这个也会重置程序计数器得到上层方法该执行的位置。前面讲的是正常退出,若抛异常没处理,继续往上找到能处 理异常的上层方法,然后返回这层方法位置,程序计数器知道异常处理的字节码行号处。
堆:存储对象的地方。堆中对象存储的数据有两种:对象头,实例域数据
对象头:分为两部分:1.存储运行时数据,包括哈希码(可能object对象的本地方法hashcode()就是返回这个值),GC分代年龄等;2.指向元数据的指针(就是指向方法区字节码的位置)
实例域数据:就是实例成员变量的数据
注:堆中对象有一个数据对齐要求,就是对象头加实例域数据的字节个数一定要是8的整数倍,不够的话,用无用字节填充。
方法区:这个地方存储JVM加载的类信息,静态变量,JIT编译器编译后的代码等数据。我们常说的常量池也在这个地方存储。
常量池:这个其实指的是运行时常量池。因为字节码文件中也有一个常量池,而这个常量池存的都是一些符号引用和字面量(符号引用可以看做就是一些用字符表示引用是什么东西,如字符“String”,表示引用的是一个字符串类型的对象。字面量的值“AA”,表示值为"AA”,这个就不多做介绍了,意如其名)。在这个字节码被加载到JVM中,相应的字节码中的常量池就是运行时常量池,JVM会对这个运行时常量池进行静态解析和动态解析(就是将符号引用变成直接引用——实实在在的对象内存地址)
注:
1.运行时常量池里存的都是堆中对象的地址,自己不存对象。
2.方法区里的类信息和静态变量实际上在字节码中,所以与其说方法区存这些信息,不如说存字节码