一:运行时数据区
(1)程序计数器:可以看成是当前线程执行的字节码的行号指示器,字节码解释器工作时就是通过改变这个计数器的值来
选取下一条需要执行的字节码指令。
如果线程执行的是JAVA方法,其记录的是正在执行的虚拟机字节码指令的地址
如果执行的是Native方法,这个计数器值为空。此区域永远不会OOM。
(2)虚拟机栈:生命周期与线程相同,线程私有,每个方法在执行的时候都会创建一个栈帧,栈帧内存放了局部变量表、操作数栈,动态链接
方法出口等信息。每一个防范调用直至执行完成的过程,对应入栈到出栈的过程。
局部变量表里面放着,基本数据类型与对象的引用。
可能抛出StackOverflowError,线程请求栈深度大于虚拟机栈深度
当虚拟机栈进行扩展时,申请不到足够的内存会抛出OOM
(3)本地方法栈
执行Native方法作用于虚拟机栈类似
也会抛出上述两种异常
(4)堆
分为新生代和老年代
新生代分为E S1 S2
(5)方法区(元空间)
存放加载的类的信息、常量、静态变量
(6)运行时常量池
当java文件被编译成class文件之后,也就是会生成我上面所说的class常量池,那么运行时常量池又是什么时候产生的呢?
jvm在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,由此可知,运行时常量池也是每个类都有一个。在上面我也说了,class常量池中存的是字面量和符号引用,也就是说他们存的并不是对象的实例,而是对象的符号引用值。而经过解析(resolve)之后,也就是把符号引用替换为直接引用,解析的过程会去查询全局字符串池,也就是我们上面所说的StringTable,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的。
-
1.全局常量池在每个VM中只有一份,存放的是字符串常量的引用值。
-
2.class常量池是在编译的时候每个class都有的,在编译阶段,存放的是常量的符号引用。
-
3.运行时常量池是在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中,也就是说,每个class都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致。
(7)直接内存
2 对象的内存布局
对象头、实例数据、对齐填充
对象头:哈希码、GC分代年龄、锁状态、线程持有的锁、偏向线程ID等