思考:Java内存模型和硬件内存模型

前言

前一阵在看volatile的原理,看到内存屏障和缓存一致性,发现再往底层挖就挖到了硬件和Java内存模型。这一块是自己似懂非懂的知识区,我一般称之为知识混沌区。因此整理这一篇文章。

什么是内存模型(Memory Model)呢?它是系统和程序员之间的规范,它规定了存储器访问的行为,并影响到了性能。并且,Memory Model有多层,处理器规定、编译器规定、高级语。对于高级语言来说,如Java内存模型, 它通常需要支持跨平台,也就是说它会基于各种不同的内存模型,但是又要提供给程序员一个统一的内存模型,可以理解为一个适配器的角色。

这篇文字主要包含了三部分:

  1. 硬件内存模型

  2. Java内存模型和运行时数据区

  3. 三者的关系

硬件内存模型

下图是2012 Sandy Bridge(一种Intel处理器)核心设计。图中有socket1和socket2,可以理解为了这台电脑中有两个插cpu的槽,每个槽中有一个多核(C1,C2...Cn)的cpu。对于CPU的内存模型可以大致按照如下进行分解:

寄存器

编译器会将本地变量和函数参数分配到这些寄存器上

内存排序缓冲(Memory Ordering Buffers)

这些缓冲用于记录等待缓存子系统时正在执行的操作

L1 缓存

空间最小,访问速度最快

L2缓存

要作用是作为L1和L3之间的高效内存访问队列。L2缓存同时包含数据和指令

L3缓存

在同插槽的所有核心都共享L3缓存。

主内存

在缓存完全没命中的情况下

简化之后如下图所示,计算机在高速的 CPU 和相对低速的存储设备(内存,RAM)之间使用高速缓存,作为内存和处理器之间的缓冲。将运算需要使用到的数据复制到缓存中,让运算能快速运行,当运算结束后再从缓存同步回内存之中。

在多处理器的系统中(或者单处理器多核的系统),每个处理器内核都有自己的高速缓存,它们有共享同一主内存(Main Memory---RAM)。

Java内存模型和运行时数据区

说完系统的内存模型,然后开始说一下Java的内存模型(Java Memory Model,简称 JMM)。

    

Java语言一大特性就是跨平台型。其背后的实现便是在Java 虚拟机规范中定义的Java 内存模型(Java Memory Model,简称 JMM)。

虚拟机通过内存模型,定义了将变量存储到内存和从内存中取出变量的底层细节(字节码指令转换是另一方面),屏蔽掉各种硬件和操作系统的内存访问差异,实现让 Java 程序在各种平台下都能达到一致的内存访问效果,不必因为不同平台上的物理机的内存模型的差异,对各平台定制化开发程序。

上面提到了两个重要的概念--内存和变量。

先说内存,Java内存模型中的内存分为两类:主内存(Main Memory)和工作内存(Working Memory,又称本地内存)。其详情如下:

主内存可以类比成物理硬件的主内存,但此处仅是虚拟机内存的部分。工作内存可以类比成处理器高速缓存

主内存是所有的线程共享,每个线程都有自己的工作内存,属于线程私有。

一个线程不能访问另一个线程的工作内存,线程之间需要通过主内存来实现线程间的通信;

线程的工作内存中保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有的操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存的变量;

如果想理解上面提到的变量(Variables)的提取和存储。那就需要继续看一下JVM另一个重要的知识点--运行时数据区。如下图所示,不同jdk版本的运行时数据区划分有所差异。但主要分为了五部分:方法区(8开始使用元数据),堆,栈,程序计数器,本地方法栈。细节就不展开讲。

内存模型中管理的变量(Variables)则主要指是堆中的数据,它包括了实例字段、静态字段和构成数值对象的元素,如数组等。但不包括Java方法中局部变量与方法参数,如果局部变量是一个 reference 类型,它引用的对象在 Java 堆中可被各个线程共享,但是 reference 本身在 Java 栈的局部变量表中。

总结一下:Java 运行时数据区和内存模型是不一样的东西,更确切的说应该是不是同一层次的东西。

  1. 内存模型:是定义了线程和主内存之间的抽象关系,更多的是定义规则

  2. 运行时数据区域:是指 JVM 运行时将数据分区域存储,强调对内存空间的划分。

硬件内存模型和Java内存模型关系

Java内存模型中的主内存和工作内存的区别在于线程调度和共享的区别,而不是物理层面的区别。因此硬是将Java内存模型和硬件内存模型进行映射没有意义。如果真的有关系,只能说工作内存更多的是CPU寄存器和缓存。当然,工作内存由于上下文切换等原因,也可能会写回RAM(可以理解为物理内存,严谨来说是物理虚拟内存)。

对于运行时数据区而言,有些是随着虚拟机启动而创建,虚拟机关闭而销毁。还有一部分是随着线程生命周期创建销毁的。

线程间共享的方法区和堆,是说它们会随着虚拟机启动而创建,随着虚拟机退出而销毁。而栈和程序计数器会随着线程开始和结束而创建和销毁。

正如下图所示,方法区和堆在RAM中,也可以在缓存中,这也是JVM创建时进行管理的内存空间。

以堆为例,由于对象实例的创建在JVM中非常频繁,一方面保证并发环境下从堆区中划分内存空间的线程安全,另一方面提升内存分配的吞吐量。对Eden区域继续进行划分,JVM为每个线程分配一个私有缓存区域--本地线程分配缓冲((Thread Local Allocation Buffer,TLAB)。而这个缓冲则缓存中,而不是RAM中

如前所述,Java内存模型和硬件内存架构是不同的。 线程栈和堆的一部分有时可能存在于CPU高速缓存和内部CPU寄存器中。 

参考资料:

https://jenkov.com/tutorials/java-concurrency/java-memory-model.html

指令重排序 - 简书

https://www.cnblogs.com/czwbig/p/11127124.html

https://zhuanlan.zhihu.com/p/51613784

Java 运行时数据区和内存模型(JMM)_jmm 和运行时数据区 的关系看-CSDN博客

简单介绍一下什么是“工作内存”和“主内存”(JMM中的概念)_工作内存和主内存-CSDN博客

JVM运行时数据区------堆_数据区和堆-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/42776.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CentOS6用文件配置IP模板

CentOS6用文件配置IP模板 到 CentOS6.9 , 默认还不能用 systemctl , 能用 service chkconfig sshd on 对应 systemctl enable sshd 启用,开机启动该服务 ### chkconfig sshd on 对应 systemctl enable sshd 启用,开机启动该服务 sudo chkconfig sshd onservice sshd start …

未羽研发测试管理平台

突然有一些觉悟,程序猿不能只会吭哧吭哧的低头做事,应该学会怎么去展示自己,怎么去宣传自己,怎么把自己想做的事表述清楚。 于是,这两天一直在整理自己的作品,也为接下来的找工作多做点准备。接下来…

LT7911UX 国产原装 一拖三 edp 转LVDS 可旋转 可缩放

2.一般说明 该LT7911UX是一种高性能Type-C/DP1.4a到MIPI或LVDS芯片的VR/显示应用。HDCP RX作为HDCP转发器的上游,可以与其他芯片的HDCP TX配合实现转发器功能。 对于DP1.4a输入,LT7911UX可配置为1/2/4通道。自适应均衡使其适用于长电缆应用,最…

Junior.Crypt.2024 CTF Web方向 题解WirteUp 全

Buy a cat 题目描述:Buy a cat 开题 第一思路是抓包改包 Very Secure App 题目描述:All secrets become clear 开题 乱输一个密码就登陆成功了(不是弱口令) 但是回显Your role is: user 但是有jwt!!&a…

记录在Windows上安装Docker

在Windows上安装Docker时,可以选择使用不同的后端。 其中两个常见的选择是:WSL 2(Windows Subsystem for Linux 2)和 Hyper-V 后端。此外,还可以选择使用Windows容器。 三者的区别了解即可,推荐用WSL 2&…

我们公司落地大模型的路径、方法和坑

我们公司落地大模型的路径、方法和坑 李木子 AI大模型实验室 2024年07月02日 18:35 北京 最近一年,LLM(大型语言模型)已经成熟到可以投入实际应用中了。预计到 2025 年,AI 领域的投资会飙升到 2000 亿美元。现在,不只…

Thinking--在应用中添加动态水印,且不可删除

Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想。 水印是一种用于保护版权和识别内容的技术,通常用于图像、视频或文档中。它可以是文本、图像或两者的组合,通常半透明或以某种方式嵌入到内容中,使其不易被移除或篡改…

【Linux】多线程_2

文章目录 九、多线程2. 线程的控制 未完待续 九、多线程 2. 线程的控制 主线程退出 等同于 进程退出 等同于 所有线程都退出。为了避免主线程退出,但是新线程并没有执行完自己的任务的问题,主线程同样要跟进程一样等待新线程返回。 pthread_join 函数…

算法学习笔记(8.2)-动态规划入门进阶

目录 问题判断: 问题求解步骤: 图例: 解析: 方法一:暴力搜索 实现代码如下所示: 解析: 方法二:记忆化搜索 代码示例: 解析: 方法三:动态规划 空间…

Qt入门(二):Qt的基本组件

目录 Designer程序面板 1、布局Layout 打破布局 贴合窗口 2、QWidget的属性 3、Qlabel标签 显示图片 4、QAbstractButton 按钮类 按钮组 5、QLineEdit 单行文本输入框 6、ComboBox 组合框 7、若干与数字相关的组件 Designer程序面板 Qt包含了一个Designer程序 &…

Django 更新数据 save()方法

1,添加模型 Test/app11/models.py from django.db import modelsclass Post(models.Model):title models.CharField(max_length200)content models.TextField()pub_date models.DateTimeField(date published)class Book(models.Model):title models.CharFie…

Spring Boot集成grpc快速入门demo

1.什么是GRPC? gRPC 是一个高性能、开源、通用的RPC框架,由Google推出,基于HTTP2协议标准设计开发,默认采用Protocol Buffers数据序列化协议,支持多种开发语言。gRPC提供了一种简单的方法来精确的定义服务&#xff0c…

UE5.3-基础蓝图类整理一

常用蓝图类整理: 1、获取当前关卡名:Get Current LevelName 2、通过关卡名打开关卡:Open Level(by name) 3、碰撞检测事件:Event ActorBeginOverlap 4、获取当前player:Get Player Pawn 5、判断是否相等&#xff1…

WEB安全基础:网络安全常用术语

一、攻击类别 漏洞:硬件、软件、协议,代码层次的缺陷。 后⻔:方便后续进行系统留下的隐蔽后⻔程序。 病毒:一种可以自我复制并传播,感染计算机和网络系统的恶意软件(Malware),它能损害数据、系统功能或拦…

C++语言学习精简笔记(包含C++20特性)

目录 1 C新语法C与CC编译运行String编程范式C基础类型**自动类型推导**统一对象初始化:Uniform Initialization 控制结构if语句for语句switch语句namespace 2 函数函数声明形式参数函数参数传递的选择函数返回值的选择 函数重载 Lambda表达式函数的定义和申明生存期…

【一】m2芯片的mac中安装ubuntu24虚拟机集群

文章目录 1. 虚拟机配置2. 复制虚拟机2.1 修改主机名2.2 修改网络 1. 虚拟机配置 在官方网站下载好ubuntu24-arm版镜像开始安装,安装使用VMWare Fusion的社区免费授权版,使用一台m2芯片的mac电脑作为物理机平台。 为什么选择ubuntu24?因为centOS7目前已…

Proteus + Keil单片机仿真教程(五)多位LED数码管的静态显示

Proteus + Keil单片机仿真教程(五)多位LED数码管 上一章节讲解了单个数码管的静态和动态显示,这一章节将对多个数码管的静态显示进行学习,本章节主要难点: 1.锁存器的理解和使用; 2.多个数码管的接线封装方式; 3.Proteus 快速接头的使用。 第一个多位数码管示例 元件…

『C + ⒈』‘\‘

&#x1f942;在反斜杠(\)有⒉种最常用的功能如下所示&#x1f44b; #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main(void) {int a 10;int b 20;int c 30;if (a 10 &&\b 20 &&\c 30){printf("Your print\n");}else{prin…

二分查找3

1. 有序数组中的单一元素&#xff08;540&#xff09; 题目描述&#xff1a; 算法原理&#xff1a; 二分查找解题关键就在于去找到数组的二段性&#xff0c;这里数组的二段性是从单个数字a开始出现然后分隔出来的&#xff0c;如果mid落入左半部分那么当mid为偶数时nums[mid1]…

ByteMD富文本编辑器的vue3配置

Git地址&#xff1a;GitHub - bytedance/bytemd: ByteMD v1 repository 控制面板输入 npm install bytemd/vue-next 下载成功后在src/main.ts中引用 import "bytemd/dist/index.css";引入后保存&#xff0c;下面是一些插件&#xff0c;比如说我用到gmf和hightLight&…