如图:
运行时数据区主要有 5个核心区;又根据是否线程私有分为两部分
线程私有:方法区(含有运行时常量池)、堆
线程共享:程序计数器、虚拟机栈、本地方法栈
方法区
各个线程共享的内存区域,又叫非堆区。用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。JDK 1.7 中的永久代和 JDK 1.8 中的 Metaspace 都是方法区的一种实现。该区域不常发生GC,主要是对常量池的回收和类的卸载。而运行时常量池时方法区的一部分,会受到方法区内存的限制,当常量池无法申请到内存时会抛出OutOfMemoryError异常。
堆
JVM管理内存中最大的一块,堆被所有线程共享,存放对象实例,几乎所有的对象实例和数组都在这里分配。堆内存没有可用空间时,将抛出OOM异常。根据对象存活周期不同,又可分为新生代、老年代。如果堆中无法分配内存并且无法扩展时,将会抛出OutOfMemoryError异常。
虚拟机栈
也叫方法栈,线程私有的。线程再执行每个方法时会同时创建一个栈帧,用来存储局部变量表、操作栈、动态链接、方法出口信息等。调用方法时执行入栈,方法返回时执行出栈。与堆的区别就是如:Obj obj=new Object();等号左边则是在虚拟机栈上分配栈区存储引用类型变量的句柄Obj obj,等号右边则是存储对象实例,栈区的句柄是指向堆区的对象实例的,一般通过句柄访问堆区的对象实例。 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果栈可以动态扩展,扩展到无法申请到足够内存时则抛出OutOfMemoryErrory异常
本地方法栈
保存线程执行方法的信息,不过是执行native方法时 才会使用本地方法栈。该区域也会抛出StackOverflowError和OutOfMemoryError异常。
程序计数器
保存当前线程执行的字节码位置,每个线程都有一个独立的计数器,程序计数器为执行Java方法服务,执行本地方法时,程序计数器为空。该区域是唯一没有不发生OOM情况。
总体结构布局以及相应的控制参数: