Java 内存区域是指 JVM 运行时将数据分区域存储 ,简单的说就是不同的数据放在不同的地方。通常又叫 运行时数据区域,分为堆、栈、方法区、程序计数器。其中栈又分为虚拟机栈和本地方法栈。
线程共享的区域为方法区和堆,线程私有的区域为程序计数器、方法区。
Java 内存模型(JMM)定义了程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。
程序计数器
线程私有。
通过改变计数器的值来选取下一条要执行字节码指令。分支、跳转、循环、异常处理、线程恢复都需要它。
为了保证线程切换后能恢复到正确的执行位置,每个线程都有1个独立的程序计数器,每个线程之间的计数器不相互影响,这就是线程私有内存。
- 如果是一个Java方法,记录的是虚拟字节码指令的地址
- 如果一个Native方法,这个计数器为空
是唯一一个虚拟机没有规定OOM的区域
虚拟机栈
线程私有。
它描述的是Java方法执行的内存模型,每个方法在执行的时候都创建一个栈帧,每个方法从执行到结束的过程就是栈帧压栈到出栈的过程。
每个栈帧都有局部变量表,局部变量表存储的是各种基本数据类型和对象引用
虚拟机规范中规定了2种异常
- StackOverflowException,当线程请求的深度大于虚拟机所允许的栈深度
- OOM,虚拟机支持动态扩展,当无法申请到足够的内存,就会抛出这个异常
本地方法栈
线程私有。
与虚拟机栈相同,不过执行的Native方法
堆
线程共享。
Java虚拟机中管理的内存最大的一块,唯一的目的就是存放对象实例,几乎所有的对象都是在这里分配内存。
是垃圾回收器管理的主要区域,现在收集器采用的基本上都是分代回收算法。Java堆可以分为新生代和年老代,新生代还可以分为Eden、From Survicor、To Survicor区域
方法区
线程共享。
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码。
这个区域的内存回收主要是针对常量池的回收和对类型的卸载。
运行时常量池是方法区的一部分,用于存放编译器生成的各种字面量和富豪已用,这部分内容将在类加载后进入方法区的运行时常量池中堆放。
如果生成了大量的类填满了方法区,会导致OOM。
其他
JDK1.8及之后,用元空间代替了方法区。
Java内存模型
- 线程之间的共享变量存在主内存中
- 每个线程都有自己私有的本地内存,存储了共享变量的本地副本
线程间的通信必须经过主内存,也就是线程A和B要通信的话,必须要经过2个步骤
- 线程A把本地内存中更新的共享变量刷新到主线程中去
- 线程B到主内存中去读取线程A之前已经更新过的共享变量
参考
https://segmentfault.com/a/1190000038190582
《深入理解JAVA虚拟机》