运行时数据区
运行时数据去分为线程私有区和线程共享区。
线程私有区域有:程序计数器、虚拟机栈、本地方法栈
线程共享区域有:堆、方法区
程序计数器
特点:
- 程序计数器是当前线程执行的字节码行号指示器。
- 字节码解释器就是通过改变程序计数器的值来实现流程控制的工作
- 保证线程发送切换之后,仍然能回到正确的执行位置。
- 每个线程都有一个程序计数器
- 当执行的是本地方法,那么计数器为空(undefined)
虚拟机栈
java虚拟机栈描述的是java方法执行的内存模型
当方法被调用时,虚拟机会创建一个栈帧来存储局部变量表、操作数栈、动态链接、方法出口。
每调用一个方法就会创建一个栈帧(一个方法对应一个栈帧)
每个方法从调用到执行完毕,对应一个栈帧的入栈和出栈。
1、局部变量表
存放编译期可以预知的各自基本数据类型,对象引用,完成内存空间的分配。
这些数据类型在局部变量表中的存储单位是以局部变量槽来表示。
long,double占两个槽,其他都是一个。
2、操作数栈
整个java虚拟机有两成栈
第一层:栈帧对应方法
第二层:操作数栈,对应方法内部执行的字节码指令
字节码指令做入栈和出栈操作,执行引擎就按照顺序执行即可
本地方法栈
跟java虚拟机栈类似的,只是管理的是native方法。
Hotspot将两者合二为一
堆
所有的对象实例以及数组都应该分配到堆上,此处是多个线程的共享区域。
垃圾回收主要针对的就是堆这个区域。
堆还分为新生代、老年代。新生代又分为Eden和survivor区,survivor区又分为survivor To和survivor From区
一般老年代是新生代的两倍,Eden和两个survivor的比例为8:1:1.
方法区
方法区和堆一样,也是线程共享的。
方法区用来存储被虚拟机加载的类信息、常量、静态变量,即时编译后的代码缓存等。
java虚拟机将方法区描述为堆的逻辑部分
Hotspot为例,JDK1.8之前采用永久代来实现方法区。
永久代实际占用的是JVM的内存,受限于JVM的大小,容易出现方法区溢出。
1.8之后,Hotspot改造,废除永久代,采用元空间的方式来实现方法区。而元空间的实现采用的是本地内存。
方法区是在堆里面吗
三种情况:
1、 java7之前,方法区位于永久代(PermGen),永久代和堆相互隔离,永久代的大小在启动JVM时可以设置一个固定值,不可变;
2、 java7中,static变量从永久代移到堆中;
3、 java8中,取消永久代,方法存放于元空间(Metaspace),元空间仍然与堆不相连,但与堆共享物理内存,逻辑上可认为在堆中