上面内存组成中,堆和方法区(JDK1.8后称为元空间)为线程共享,其余均为线程独占。
另一说 JVM 内存由7部分组成,这是因为单独计算了 运行时常量池(它是方法区的一部分) 并额外计算了直接内存(但其实它不是JVM内部的一部分)
程序计数器(Program Counter Register)
程序计数器是线程独立的
用于记录当前线程下一条需要被执行的指令
虚拟机栈(Java Stack)
也称java 栈、线程栈,
线程独立,生命周期同线程
包含多个栈帧:方法执行时为其分配的栈空间
默认大小约 1M,与操作系统主机配置有关
用于存储下面几种数据:
示例代码
public static int a(){
int a = 1;
return a;
}
public static void main(){
System.Out.Println(a());
}
main 方法调用 a 方法时,是通过动态链接找到的 a 方法
a 方法中对局部变量 a 进行赋值时,会先将 1 压入操作数栈,然后在局部变量表中开辟空间存放变量 a ,再从操作数栈弹栈赋值给变量 a
执行结束后,通过方法出入口记录的地址找到 main 方法调用 a 方法的位置进行返回并是不接下来要执行的程序
本地方法栈(Native Method Stack)
Native 方法使用的内存空间
堆(Heap)
所有线程共享
java中所有对象实例以及数组都存放在堆中
是垃圾收集器主要管理的区域
默认大小约 1/64(初始) 到 1/4(最大) 物理内存
组成
方法区
JDK 1.8 以后叫 元空间,1.8 以前叫 永久代。
所有线程共享
用于保存
常量、静态变量 的对象 在堆里
从下面案例可以看到静态变量与常量的对象时在堆里的,但其引用应该是在方法区(否则没法解释)
public class MetaspaceBoomDemo {
static byte[] a = new byte[10 * 1024*1024];//静态变量 10M
// public static final byte[] a = new byte[10 * 1024*1024];//常量 10M
public static void main(String[] args) {
System.out.println(new MetaspaceBoomDemo());
}
}
堆 3M ,元空间 30M:-Xms3m -Xmx3m -XX:MetaspaceSize=30m
,爆炸了
堆 30M ,元空间 3M:-Xms30m -Xmx30m -XX:MetaspaceSize=3m
,没事
JVM 的直接内存,是 JVM 直接使用的 JVM 之外的内存
默认大小约 1/4(最大) 物理内存(与 JVM 堆一致)
直接内存的作用主要包括
ByteBuffer.allocteDirect(capability)
在直接内存中划分区域使用JMM 是 java 内存模型:java Memory Model ≠ JVM 内存模型
JMM 本身是一个抽象概念,并不真实存在
JMM 描述了一组规则规范,通过它定义了程序中各个变量的访问方式
上述变量包括成员变量、静态变量和集合中的元素
JMM 内存模型
示意图
概念
主内存
也可以理解为 共享内存
JMM 将大部分变量都视为存储在 主内存 中,这些变量都可能被多线程同步访问操作
本地内存
也可以理解为 工作内存,对线程而言是私有的
工作内存是相互隔离的,其互相访问需要通过主内存
线程操作共享内存中变量的流程
JMM 工作流程