Java 内存模型和硬件内存架构笔记

前言

可跟《主存存取和磁盘存取原理笔记》串着看

https://blog.csdn.net/suifeng3051/article/details/52611310

杂技

Java 内存模型(堆栈)

Jvm 内部,Java 内存模型把内存分成了两个部分:线程栈区和堆区:

栈区包含:线程执行信息(线程栈),本地原始类型变量(boolean,byte, short, int, long, float, double)
堆区包含:Java 应用创建的所有对象信息,基础类型的封装类

  1. 一个本地变量如果是原始类型,存储栈中
  2. 一个本地变量是一个对象的引用,那么这个本地引用存储栈,对象本身存储堆中
  3. 一个对象的成员方法,存储栈中,方法中包含的原始类型变量,存储堆中
  4. 一个对象的成员变量,无论是原始类型还是包装类型,都存储堆中
  5. 堆中数据可被多个线程共享,对于原始类型变量,每个线程都会拷贝一份

硬件内存架构

不管什么内存模型,最终还是运行在计算机硬件上,因此有必要了解计算机硬件的内存架构

  1. 现在计算机一般都有2个以上cpu, 每个cpu还有多个核心,线程会在各个cpu核心中并行运行
  2. CPU 内部会有一组CPU 寄存器、CPU 缓存(一级,二级,三级缓存),RAM主存
  3. 存储速度: CPU 寄存器 > CPU 缓存(一级> 二级> 三级) > RAM
  4. 存储大小 CPU 寄存器(64 bit) < CPU 缓存[一级(64k)> 二级(256k)> 三级(8MB)] < RAM(4G)

线程间的竞争现象

  1. 存在 count 为1, 两个线程都在缓存中保存一份备份
  2. 两个线程分别改变 count 的值,存在写缓存,顾缓存和 RAM的值存在偏差
  3. 当写缓存的数据 flush 到 RAM 就发生冲突了

内存屏障(Memory Barrier):

  1. 内存屏障,又称内存栅栏,是一个CPU 指令
  2. 保证特定操作的执行顺序。编译器和CPU会重排序指令,为了优化,插入内存屏障指令会让CPU不把这条指令重排序。
  3. 影响某些数据(或某条指令的执行结果)的内存可见性。强制刷新各种CPU cache, 写缓存的数据直接写入RAM,读缓存重新读取数据

内存屏障和 Java 有什么关系?

volatile 是基于 Memory Barrier 实现的。

这意味着,如果写入一个 volatile 变量a,可以保证:

  1. 一个线程写入变量a 后,任何线程访问该变量都会拿到最新值
  2. 由于会刷新 Cache中所有先前写入,因此写入变量a之前的写入操作,其更新的数据对于其它线程也是可见的
原文地址:https://www.cnblogs.com/haichao/p/9011310.html