Runtime Data Area运行时数据区
概念
见名知意,就是JVM运行时的数据区,我们需要的数据一般都在这里.
前面已经知道,一个class文件,经过load-link-initialize加载到JVM.
然后,就是经过运行时引擎(run engine)进入运行时数据区(runtime data area).
最权威的参考文档:Java Virtual Machine Specification
结构
总体上分为线程私有和线程共享的两类:
- 每个线程私有的区域: PC,VMStack,NativeMethodStack
- 所有线程共享的区域:Heap,MethodArea,DirectMemory
(MethodArea的实现:当JDK<1.8时 由PermSpace实现, 当JDK>=1.8时由MetaSpace实现)
每个区域详情:
- Program Counter(PC)程序计数器: 存放指令位置,虚拟机不断的从PC中取出下一条指令的位置,找到指令去执行
- heap堆:对象存放的地方,所有线程共享. 重点,后面GC详细学
- JVM stacks: JVM管理的栈,每个线程有自己私有的JVM stack,其中的每个方法对应一个栈帧(frame). 重点
- native method stacks本地方法栈:线程私有,通过JNI等调用C和C++方法时用的栈
栈包括JVM stacks和native method stacks
平时一般说到栈,指的都是JVM stacks
- Direct Memory直接内存: 从JVM内可以访问OS管理的内存(内核空间),可以提高IO效率(零拷贝),JDK1.4新增的.
比如一个网络请求传过来一个数据到OS内核空间中,1.4以前使用这个数据时需要把内核空间中的数据拷贝到JVM内存中;
1.4之后,通过NIO可以使用直接内存,直接访问内核空间的该数据,不需拷贝. - method area方法区:class结构存放的地方,所有线程共享
方法区中还有块 run-time constant pool 常量池,存放class文件的常量池(constant_pool)
方法区是一个逻辑上的概念
JDK1.8之前,方法区由永久区(Permament Space)实现,字符串常量也在永久区,FGC不会清理;JVM启动时指定永久区空间大小,不能改变
自JDK1.8开始,方法区由Meta Space实现,字符串常量位于堆,会触发FGC 被清理.可以指定大小,如果不指定的话,最大就是物理内存空间.
栈帧Frame
A Frame is used to store data and partial results,as well as to perform dynamic linking,return values for methods,and dispatch exceptions.
主要包括:
- 局部变量表(local variable table)
注意,形参也在局部变量表;如果是成员方法,this也在局部变量表
变量表从下标0开始,排序优先级为:this > 形参 > 方法中的变量
形参和方法中的变量按出现的顺序排列 - 操作数栈(Operand Stacks)
里面存的是一个个操作数,比如_load指令会把一个值压栈,_store指令会把栈顶的值弹出.
对于long的处理(store and load),多数虚拟机的实现都是原子的
jls 17.7,没必要加volatile
- dynamic linking,
指向运行时常量池
比如a() -> b(),方法a调用了方法b,class文件解析时把方法放在运行时常量池中了,这个就是用来找到b
jvms2.6.3
https://blog.csdn.net/qq_41813060/article/details/88379473 - return address
a() -> b(),方法a调用了方法b, b方法的返回值放在什么地方
栈的指令集
这个指令集是JVM很底层的东西了,这个看明白了,任何其他语言也就很容易理解了,大家都差不多.
马老师说:别人看山是山,你看山是看到的都是各种分子,所以任何的山都是一样的.哈哈哈
第一个境界是 看山是山;
第二个境界是 看山不是山;
第三个境界是 看山还