Jvm内存
2020/7/27大约 3 分钟
内存区域

程序计数器
每个线程都有一个独立的程序计数器,指向当前执行的行号。正在执行Java方法的话,计数器记录的是虚拟机字节码指令的地址(当前指令的地址)。如果是Natice方法,则为空。
Java 虚拟机栈
每个方法在执行的时候也会创建一个栈帧,存储了局部变量,操作数,动态链接,方法返回地址。
- 每个方法从调用到执行完毕,对应一个栈帧在虚拟机栈中的入栈和出栈。
- 局部变量所需内存在编译期间完成分配。
- 如果线程请求的栈深度大于虚拟机所允许的深度,则StackOverflowError。
- 如果虚拟机栈可以动态扩展,扩展到无法申请足够的内存,则OutOfMemoryError。
本地方法栈
和虚拟机栈类似,主要为虚拟机使用到的Native方法服务。
- 也会抛出StackOverflowError 和 OutOfMemoryError。
Java堆
被所有线程共享的一块内存区域,在虚拟机启动的时候创建,用于存放对象实例。
- 对可以按照可扩展来实现(通过-Xmx 和-Xms 来控制)
- 当堆中没有内存可分配给实例,也无法再扩展时,则抛出OutOfMemoryError异常。
方法区
被所有方法线程共享的一块内存区域。
- 用于存储已经被虚拟机加载的类信息,常量,静态变量等。
- 这个区域的内存回收目标主要针对常量池的回收和堆类型的卸载。
- 老版本方法区也被称为永久代,jdk8真正开始废弃永久代,而使用元空间(Metaspace)。
内存模型JMM

定义
JMM定义了线程和主内存之间的抽象关系。
线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程读/写共享变量的副本。
JMM内存模型三大特性
原子性:
- AtomicInteger类类。
- 使用 synchronized 互斥锁来保证操作的原子性。
可见性:
- synchronized,对一个变量执行 unlock 操作之前,必须把变量值同步回主内存。
- volatile,会强制将该变量自己和当时其他变量的状态都刷出缓存。
- final,被 final 关键字修饰的字段在构造器中一旦初始化完成。
有序性:
- 源代码 -> 编译器优化的重排 -> 指令并行的重排 -> 内存系统的重排 ->最终执行的命令。
- 重排序过程不会影响到单线程程序的执行,却会影响到多线程并发执行的正确性。
操作指令
指令 | 名称 | 描述 |
---|---|---|
lock | 加锁 | 作用于主内存的变量 |
unlock | 解锁 | 作用于主内存的变量 |
read | 读取 | 读取主内存的变量 |
load | 加载 | 将读取的主内存变量加载到工作副本中 |
use | 使用 | 把工作内存中的变量传递给执行引擎 |
assign | 赋值 | 将执行引擎接收到的值赋值给工作内存变量 |
store | 存储 | 作用于工作内存,将工作内存变量传递到主内存 |
write | 写入 | 作用于主内存,将从工作副本store的值写入主内存中 |