1、程序计数器
程序计数器是一块较小的是内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
程序计数器是线程私有的(也就是线程隔离的数据区),主要是为了线程在切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间的计数器互不影响,独立存储(这就是线程私有)。
如果程序正在执行的是一个java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;
如果程序正在执行的是native(本地)方法时,则计数器的值是空值(undefined)。
程序计数器是唯一一个没有内存溢出情况的区域。
2、java虚拟机栈
Java虚拟机栈也是线程私有的,它的生命周期和线程的生命周期是相同的。
Java虚拟机栈描述的是java方法执行的内存模型:每一个方法被执行时,都会创建一个栈帧,用于存储局部变量表、动态链接、方法出口等信息。
每一个方法从调用到执行完成的过程,就对应着一个栈帧在虚拟机中从入栈道出栈的过程。
平常我们所说的栈就是指的是虚拟机栈中的局部变量表,局部变量表主要存储的是编译期可知的各种基本数据类型(8种基本数据类型)、对象引用和指向一条字节码指令的地址。
Java虚拟机栈中规定了两种异常:
(1)、如果线程请求的栈深度大于虚拟机栈所允许的深度,组会抛出栈溢出异常。
(2)、如果虚拟机栈可以动态的扩展,但是当扩展无法申请到足够的内存时,就会抛出内存溢出异常。
3、本地方法栈
本地方法栈和java虚拟机栈的非常相似,两者的区别在于:java虚拟机栈执行java方法服务,而本地方法栈则执行native(本地)方法服务,
本地方法栈也会抛出栈溢出异常和内存溢出异常。
4、java堆
Java是java虚拟机中所管理的内存中最大的一块,java对是被所有线程共享的一块内存区域,在虚拟机启动的时候创建。
Java堆唯一的目的就是存放对象实例(也就是我们一般使用new关键字创建的对象),所有的对象实例都会在java堆中分配内存。
将new的对象分配在栈上,而不分配在堆上,可以采用方法逃逸分析技术实现。
Java堆是垃圾回收器管理的主要区域,目前垃圾回收器基本采用的是分代收集算法,所以java堆可以分为:新生代和老年代;
新生代可以分为两种:(1)、Eden空间(2)、Servivor Space(From Servivor 空间, To Servivor空间)。
5、方法区
方法去是用来存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
各个线程都可以访问虚拟机加载的类。
当方法区无法满足内存分配需求时,将抛出内存溢出异常。