Runtime Data Area
Runtime Data Area指的是Java在运行时的数据区,也就是JVM的内存模型
1.Program Counter
- 简称PC,程序计数器,用于存放指令的位置
- 取PC中的位置,找到对应的指令,执行指令,最后PC++,只要还有指令,就会一直循环这个操作
2.JVM Method Stacks
- JVM的栈,线程独有的,栈里面是一堆栈帧(frame)
- 每个线程对应一个栈,每个方法对应一个栈帧
3.Native Method Stacks
- 本地方法栈,也就是C/C++使用的栈
- 无法对这块内容进行调优,也无法进行管理
4.Method Area
- 方法区,内部是各种的Class的结构,Class的元信息,以及运行时常量池(Runtime Constant Pool)的内容
- 方法区在1.7中叫永久代,在1.8中叫元数据区,是被线程共享的
- Perm Space和Meta Space是方法区的实现
○ Perm Space (<1.8)永久代 :
字符串常量位于Perm Space
FGC不会清理
大小启动的时候指定,不能改变
○ Meta Space (>=1.8) 元数据区:
字符串常量位于堆
会触发FGC清理
不设定的话,最大就是物理内存
5.Heap
- 堆,JVM线程之间共享
Direct Memory
- 直接内存,可以直接从用户态去访问的内核态的内存,不归JVM直接管,归操作系统管
- 以前的IO要使用操作系统的内存,需要拷贝一份到JVM中
- 现在NIO使用直接内存,实现了zero copy,不需要拷贝,直接访问
补充
- 每个线程都有自己的PC,JMS,NMS
- Heap和Method Area在线程间是共享的
- Direct Memory是一种机制,严格来说不属于内存模型
栈帧 Frame
- 主要用与存储数据和数据计算的中间结果,以及执行动态链接
- 栈帧中主要分为四块内容
○ Local Variables Tables 局部变量表
局部变量表类似于寄存器,存储方法中的局部变量,从0开始计位置
非静态发方法,局部变量表中的第一项是this,静态方法在局部变量表中没有this
○ Operand Stacks 操作数栈
主要用于保存计算的中间结果,同时作为计算过程中变量的临时存储空间
○ dynamic linking 动态链接
就是A方法调用了B方法,A就会去常量池里找B的符号链接,看有没有解析,解析了用拿来用,没解析就动态解析
○ return address 返回值地址
就是A方法调用了B方法,B的返回值应该放到什么地方去,这个地址就是返回值地址
对象创建细节知识
- new完对象后,地址会压栈,这个时候,对象里面的值为默认值
- 栈里面的地址会复制一份,两个地址都会指向那个对象
- 然后回从栈中弹出一个地址,给invokespecial指令用来执行构造方法,执行后默认值变为初始值,对象创建完成
- 最后会把剩下的那个地址弹栈,建立引用,也就是赋值的过程,赋值后引用会再次被压栈,至此对象创建就算彻底结束了
i++和++i
- int i = 8
○ bipush 8:把byte类型的8变为一个int值,压到栈中(数值会根据大小改变对应的类型,比如300就会是sipush 300)
○ istore_1:把int值弹出存储到局部变量表中1的位置
- i = i++;
○ i 会先被压到栈中,
○ 在局部变量表中的 i 执行++操作变成9
○ 最后执行赋值,从栈中赋值到变量表中,又变回了8
- i = ++i;
○ i 会先执行++操作,变为9
○ 然后才会被压到栈中,最后赋值回来就是9
指令
- 指令集设计分为两种
○ 一种是基于栈的指令集,设计比较简单
○ 一种是基于寄存器的指令集,效率快,设计比较复杂,但是指令集最后都是要基于寄存器
- store:写
- load:读
- pop:弹出
- mul:乘法
- sub:减法
- invoke
○ InvokeStatic:调用类方法,也就是静态方法
○ InvokeVirtual:调用对象的实例方法
○ InvokeInterface:调用接口方法,找到实现这个接口的对象,调用方法
○ InovkeSpecial:调用特殊的实例方法,不需要多态的方法,比如private 方法 , 构造方法
○ InvokeDynamic:lambda表达式,反射,CGLib和ASM,其他动态语言scala kotlin,等动态产生的Class,会用到这个指令