1、程序计数器
程序计数器也叫PC
计数器,用于记录程序当前所运行到的指令行。在多线程中,CPU会对就绪状态的线程进行随机调度,此时就需要程序计数器来记录不同线程所执行到的位置。
程序计数器是唯一
不会发生OOM(OutOfMemory)的地方。
2、Java虚拟机栈
虚拟机栈主要是用于普通方法。每个方法在执行的时候都会创建一个栈帧,其包含了局部变量表
、操作数栈
、动态链接
、返回出口
。 局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、 float、long、double)、对象引用(reference类型,它并不等同于对象本身,可能是一个指向对象起始 地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress 类型。
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常(疯狂递归调用并且没有出口);如果Java虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的内存会抛出OutOfMemoryError异常。
3、本地方法栈
本地方法栈就是执行本地方法,即native方法
。
4、Java堆
堆是存放对象实例。1.8后常量池从方法区迁移到了堆中。
5、方法区
主要存放静态变量、相关类信息、常量、运行时常量池,(以前也叫永久代,跟堆在一块);1.8以后叫元空间,放在直接内存(因为在之前,使用HotSpot虚拟机。堆跟方法区使用同样的垃圾回收器,在堆中随时可能产生垃圾;但是在方法区可能要很久才会产生垃圾。相当于叫人不停的去打扫比较干净的区域,浪费了性能。所以在1.8后就放到直接内存去,采用不同的垃圾回收器进行回收,带来了一定的效率)。
6、直接内存
在引用NIO加入了缓冲区以后,避免操作系统不断的进行读写拷贝,实现零拷贝操作。直接在宿主机内存区域中划出一块直接内存。该区域不属于虚拟机规范,即不算运行时数据区,但是因为被频繁使用,所以才划出这一块。在java堆内可以用directByteBuffer对象直接引用并操作。虽然不属于虚拟机规范,但是也是可控制的,并且也会发生OOM的错误。
7、1.8后内存模型