基础 | JVM - [内存模型 & JMM]

§1 JVM 内存模型简介

在这里插入图片描述

上面内存组成中,堆和方法区(JDK1.8后称为元空间)为线程共享,其余均为线程独占。
另一说 JVM 内存由7部分组成,这是因为单独计算了 运行时常量池(它是方法区的一部分) 并额外计算了直接内存(但其实它不是JVM内部的一部分)

§1.1 程序计数器(Program Counter Register)

程序计数器是线程独立的
用于记录当前线程下一条需要被执行的指令

§1.2 虚拟机栈(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 方法的位置进行返回并是不接下来要执行的程序

§1.3 本地方法栈(Native Method Stack)

Native 方法使用的内存空间

§1.4 堆(Heap)

所有线程共享
java中所有对象实例以及数组都存放在堆中
是垃圾收集器主要管理的区域
默认大小约 1/64(初始) 到 1/4(最大) 物理内存
组成

  • 新生代
    • 伊甸
      • TLAB:Thread Allocation buffer
        jvm 在 eden 中给每一个线程划分的一块缓冲区,用于加速对象空间分配
        TLAB 是线程独占的
        对象优先在此空间中分配,若对象过大,依然分配与 Eden 的共享内存中
    • 幸存区 0(FROM)
    • 幸存区 1 (TO)
  • 老年代
§1.5 元空间

JDK 1.8 以后叫 元空间,1.8 以前叫 永久代。
所有线程共享
用于保存

  • 类信息
  • 常量
  • 静态变量
  • 即时编译器编译后的代码缓存

常量池
常量池有 3 种

  • 静态常量池
  • 运行时常量池:其实就是静态常量池的内容被运行时加载到内存后的状态
  • 字符串常量池


常量、静态变量 的对象 在堆里
从下面案例可以看到静态变量与常量的对象时在堆里的,但其引用应该是在方法区(否则没法解释)

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,没事
在这里插入图片描述

准确的讲,三大常量池、类信息的内存分布其实如下图
在这里插入图片描述

§2 JVM 的直接内存

JVM 的直接内存,是 JVM 直接使用的 JVM 之外的内存
默认大小约 1/4(最大) 物理内存(与 JVM 堆一致)
直接内存的作用主要包括

  • JDK 8 及之后版本的 Metaspace 是直接保存在直接内存的
    但要注意 JDK 6 及以前的 字符串常量池 是在永久代(JDK 7 及以前的方法区)中的,从 7 开始放到 里面了
  • NIO 在使用过程中可以通过 ByteBuffer.allocteDirect(capability) 在直接内存中划分区域使用
    此方式因为避免了在 Java 堆Native 堆 之间来回复制数据,所以相对较快
    但是若不断分配直接内存,JVM 堆内存使用较少,JVM 就不会触发 GC ,当直接内存先分配满还没 GC 时,会出现 OOM:Direct buffer memory

§3 JMM 内存模型

JMM 是 java 内存模型:java Memory Model ≠ JVM 内存模型
JMM 本身是一个抽象概念,并不真实存在
JMM 描述了一组规则规范,通过它定义了程序中各个变量的访问方式
上述变量包括成员变量、静态变量和集合中的元素

JMM 内存模型
示意图
在这里插入图片描述
概念
主内存
也可以理解为 共享内存
JMM 将大部分变量都视为存储在 主内存 中,这些变量都可能被多线程同步访问操作

本地内存
也可以理解为 工作内存,对线程而言是私有的
工作内存是相互隔离的,其互相访问需要通过主内存

线程操作共享内存中变量的流程

  • 从主内存复制变量进线程的工作内存中
  • 操作变量副本
  • 操作结果同步回主内存
    • 线程解锁前,必须将共享变量的值刷新会主内存
    • 线程加锁前,必须读取主内存的值到自己的工作内存
    • 加锁和解锁是对于同一把锁

JMM 工作流程

  • read
    作用于主内存
    从主内存将值传输到工作内存
  • load
    作用于工作内存
    将 read 到的值存入工作内存变量副本中
  • use
    作用于工作内存
    将工作内存变量副本的值传递给 CPU
    每次使用到变量都会执行此操作
  • assign
    作用于工作内存
    将 CPU 处理后的结果赋值给工作内存变量副本
    每次给变量赋值时,都会执行此操作
  • store
    作用于工作内存,将工作内存变量副本的值写回主内存(值传递给主内存)
  • write
    作用于主内存,将 store 传输的值写回主内存变量
  • lock
    作用于主内存
    为防止线程安全问题,将变量标记为线程独占
    只锁了写变量的过程
  • unlock
    作用于主内存
    释放锁定状态的变量
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值