1、JVM运行时数据区 (JVM Runtime Data Area)
Java虚拟机的运行时数据区一共包括以下的这么多区域:
-
- PC(Program Counter)程序计数器;
- JVM stacks (java虚拟机栈);
- NM stacks(Native Method Stacks :本地方法栈);
- Heap(堆) --垃圾回收(GC)的主要区域
- Method Area(方法区)
1.1、PC(Program Counter)程序计数器
Program counter 简称PC,指的是存放下一条指令的位置的这么一个区域。它是一块较小的内存空间,且是线程私有的。
问题:为什么程序计数器是线程私有的,不能线程共享?
因为线程的切换,CPU在执行的过程中,一个线程执行完了,接下来CPU切换到另一个线程去执行,另外一个线程执行完再切回到之前的线程,这时需要记住原线程的下一条指令的位置,所以每一个线程都需要有自己的PC。
1.2、JVM stacks (java虚拟机栈)
Jvm stacks 是线程私有的,他的生命周期和线程的生命周期是一致的。里面装的是一个一个的栈帧,每一个方法在执行的时候都会创建一个栈帧,栈帧中用来存放(局部变量表 操作数栈 动态链接 返回地址);在Java虚拟机规范中,对此区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出Stack OverflowError异常;如果虚拟机栈可以动态扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
- 局部变量表:局部变量表是一组变量值存储空间,用来存放方法参数、方法内部定义的局部变量。局部变量表的容量是以变量槽(variable slot)为最小的单位。Java虚拟机没有明确规定一个slot所占的空间大小。只是导向性的说了每一个slot能存放8中基本数据类型中的一种(long 和double这种64位的需要两个slot);
- 操作数栈:是用来记录一个方法在执行的过程中,字节码指令向操作数栈中进行入栈和出栈的过程。大小在编译的时候已经确定了,当一个方法刚开始执行的时候,操作数栈中是空发的,在方法执行的过程中会有各种字节码指令往操作数栈中入栈和出栈。
- 动态链接:因为字节码文件中有很多符号的引用,这些符号引用一部分会在类加载的解析阶段或第一次使用的时候转化成直接引用,这种称为静态解析;另一部分会在运行期间转化为直接引用,这部分称为动态链接。
- 返回地址(returnAddress):类型(指向了一条字节码指令的地址)
1.3、NM stacks(Native Method Stacks :本地方法栈)
本地方法栈和虚拟机栈类似,不同的是虚拟机栈服务的是Java方法,而本地方法栈服务的是Native方法。在HotSpot虚拟机实现中是把本地方法栈和虚拟机栈合二为一的,同理它也会抛出StackOverflowError和OOM异常。
1.4、Heap(堆)
对象的实例以及数组的内存都是要在堆上进行分配的,堆不在被线程所独有,而是线程共享的一块区域,它的确是用来存放对象实例的,也是垃圾回收(GC)的主要区域;
堆细分:新生代(Young Generation)和老年代(Old Generation),对于新生代又分为:Eden区和Surviver1(s0 s1 From Survivor)和Surviver2(s1 s2 To Survivor)区;堆同样会出现oom(设置JVM参数” -Xms20M -Xmx20M“)。
1.5、Method Area(方法区)
对于JVM的方法区也可以称之为永久区,(permanent generation)它储存的是已经被java虚拟机加载的类信息、常量(常量从jdk1.7开始就移到堆中了)、静态变量等。
Jdk1.8以后取消了方法区这个概念,称之为元空间(MetaSpace);所以在JDK1.8之后-XX:MaxPermSize 参数已经没有意义了,取代它的是”-XX:MetaspaceSize“和”-XX:MaxMetaspaceSize”等。