java-内存模型
引言
计算机程序每条指令都由CPU执行,执行过程中会对数据进行操作,程序运行时的临时数据都储存在内存中。
但是CPU执行指令的速度远远大于内存读取/写入速度,如果每次操作都需要对内存进行一次操作会大幅度降低CPU运行速度,所以CPU引入高速缓存(L1/L2/L3)来提高读写速度,如果需要对某条数据进行操作,CPU会从内存中复制数据到高速缓存中,然后对其进行一系列操作操作,结束后刷新到内存里。
引入高速缓存很好的解决了CPU执行的效率问题,但引发了一致性问题,即在多核心状态下,每个核心都有自己的高速缓存,无法保证同一数据不同核心下的高速缓存是一致的。
CPU通过缓存一致性协议来解决了这个问题,例如Intel MESI协议,这里不做过多说明。
Java虚拟机中定义了一种类似的Java内存模型,来屏蔽各硬件平台和操作系统之间的差异以及提高程序运行效率。
内存模型
- 堆内存 共享区域 java虚拟机管理的最大内存区域,几乎所有的对象都会在此区域分配。 在需要时自行扩展,可以通过-Xmx|-Xms来控制大小,当此区域内存回收后无法为新对象分配空间且无法扩展,则会抛出OutOfMemoryError异常
- 方法区 共享区域 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
- 栈内存 线程私有 用于存储局部变量表、操作栈、动态链接、方法出口等信息。 该区域内存用尽会抛出StackOverFlow异常,常见于递归操作,可以通过-Xss参数来调解栈内存大小
- 本地方法区 线程私有 为Native方法服务,规范中并未明确定义数据结构和使用方式
- 程序计数器 线程私有 用于记录当前执行的字节码的行号,java虚拟机利用计数器来实现循环、跳转以及线程切换恢复执行。
运行机制
所有对象都储存在主内存中,不包括局部变量和方法参数,局部变量与方法参数是线程私有的。
每个线程还有自己的工作内存,类似于CPU的高速缓存。当每个线程工作时会从主内存中拷贝一份数据到工作内存,在工作内存进行操作,操作完成后才会刷新到主内存中。