当前位置: 首页 > news >正文

JVM 主副内存 详解

在 JVM (Java Virtual Machine) 中,内存的设计主要分为主内存和工作内存(又称为线程内存)。这种设计是基于 Java 内存模型(Java Memory Model, JMM) 的规定,它确保了多线程环境下数据的一致性和线程间的通信。


1. 主内存与工作内存的概念

1.1 主内存

  • 主内存是所有线程共享的内存区域,主要存储程序中所有的实例对象和类变量
  • 它对应于 JVM 堆内存(Heap)和方法区(Method Area)。
  • 主内存中的数据是线程共享的,因此线程之间通过主内存通信。

1.2 工作内存

  • 工作内存是线程的私有区域,用于存储线程从主内存中拷贝的数据的副本。
  • 它对应于线程栈(Thread Stack),存放线程独立的局部变量、操作栈和部分对象引用。
  • 每个线程只能访问自己的工作内存,不能直接操作其他线程的工作内存。

2. 主内存与工作内存的关系

主内存和工作内存的关系类似于共享内存与高速缓存之间的关系:

  1. 线程对变量的所有操作(读取、写入)都必须先在工作内存中进行。

    • 线程从主内存将变量值读取到工作内存中。
    • 对变量的修改也会先在工作内存中完成,然后再同步回主内存。
  2. 线程不能直接操作主内存中的变量,所有变量必须通过工作内存中转。

示意图

主内存 (共享变量)↑   ↓
工作内存 (线程1)↑   ↓
工作内存 (线程2)

3. 主内存与工作内存的交互

JMM 定义了一组原子操作来完成主内存与工作内存之间的交互:

操作描述
lock把主内存中的变量标记为线程独占状态。
unlock解除对主内存变量的独占状态,释放给其他线程使用。
read从主内存中读取变量值到工作内存。
load把工作内存中的变量加载到线程的工作内存中。
use把工作内存中变量的值传递给执行引擎。
assign把执行引擎的值赋值给工作内存中的变量。
store把工作内存中的变量值写回主内存。
write把主内存的变量值更新为工作内存中的值。

交互流程

以变量 x 为例:

  1. 读取过程:线程从主内存中 read x,然后 load x 到工作内存。
  2. 操作过程:线程在工作内存中 use xassign x 进行计算。
  3. 写入过程:线程将工作内存中 store x,然后 write x 更新到主内存。

4. 主内存和工作内存的特点

4.1 主内存

  • 线程共享:主内存是所有线程共享的,用于存储全局变量、类变量和堆上的对象。
  • 数据一致性:主内存是线程间通信的桥梁,所有线程对共享变量的修改都必须最终同步到主内存。

4.2 工作内存

  • 线程私有:工作内存是每个线程独立的,用于存储线程从主内存中拷贝的变量值。
  • 临时存储:工作内存中的变量值只是主内存的一个副本,线程操作完成后需要同步回主内存。
  • 提高效率:减少线程对主内存的频繁访问。

5. 主内存与工作内存的典型问题

5.1 可见性问题

  • 如果一个线程修改了变量的值,但没有及时刷新到主内存,其他线程无法感知到最新的变量值。
  • 示例
    public class VisibilityExample {private static boolean flag = true;public static void main(String[] args) {new Thread(() -> {while (flag) {// 如果flag没有及时刷新到主内存,该线程可能无法退出循环}}).start();new Thread(() -> {flag = false; // 修改flag值,但未及时刷新到主内存}).start();}
    }
    

5.2 指令重排序问题

  • JVM 或 CPU 可能会对代码的执行顺序进行优化,导致线程看到的操作顺序与程序代码不一致。
  • 示例
    public class ReorderingExample {private static boolean flag = false;private static int value = 0;public static void main(String[] args) {new Thread(() -> {value = 42; // 可能先执行flag = true;}).start();new Thread(() -> {if (flag) {System.out.println(value); // 可能输出 0 而不是 42}}).start();}
    }
    

5.3 解决方法

  • 使用 volatile
    • 保证变量的可见性和禁止指令重排序。
  • 使用同步机制
    • 通过 synchronized 或锁机制来确保线程间的同步。

6. 主内存与 JVM 内存结构的关系

主内存主要对应于以下 JVM 内存区域:

  1. 堆内存(Heap)
    • 存储对象实例,所有线程共享。
  2. 方法区(Method Area)
    • 存储类信息、常量池和静态变量,所有线程共享。

工作内存主要对应于以下 JVM 内存区域:

  1. 线程栈(Thread Stack)
    • 存储局部变量和操作栈,每个线程独立。
  2. 程序计数器(Program Counter)
    • 跟踪当前线程执行到的字节码指令,每个线程独立。

7. 实际应用中的主内存与工作内存

7.1 可见性问题与 volatile

volatile 关键字确保变量的修改对所有线程可见,防止工作内存中的值与主内存不一致。

示例:
public class VolatileExample {private static volatile boolean flag = true;public static void main(String[] args) {new Thread(() -> {while (flag) {// 保证线程可以感知flag的最新值}}).start();new Thread(() -> {flag = false; // 修改flag值}).start();}
}

7.2 同步问题与 synchronized

synchronized 确保线程对共享资源的访问是互斥的,且修改后的变量会立即同步到主内存。

示例:
public class SynchronizedExample {private static int counter = 0;public static synchronized void increment() {counter++;}public static void main(String[] args) {Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) increment();});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) increment();});t1.start();t2.start();try {t1.join();t2.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Counter: " + counter); // 输出: 2000}
}

8. 总结

  • 主内存:存储共享数据,所有线程可访问。
  • 工作内存:线程私有,存储主内存变量的副本。
  • 典型问题:可见性问题、指令重排序、竞态条件。
  • 解决方法:使用 volatile 保证可见性,使用 synchronized 保证原子性和可见性。

这种主内存-工作内存的模型是 Java 内存模型的核心,帮助开发者在多线程环境下编写安全的并发程序。

相关文章:

JVM 主副内存 详解

在 JVM (Java Virtual Machine) 中&#xff0c;内存的设计主要分为主内存和工作内存&#xff08;又称为线程内存&#xff09;。这种设计是基于 Java 内存模型&#xff08;Java Memory Model, JMM&#xff09; 的规定&#xff0c;它确保了多线程环境下数据的一致性和线程间的通信…...

sscanf与sprintf函数

本期介绍&#x1f356; 主要介绍&#xff1a;sscanf()、sprintf()这对输入/输出函数&#xff0c;并详细讲解了这两个函数的应用场景。 概述&#x1f356; 在C语言的输出和输入库中&#xff0c;有三对及其相似的库函数&#xff1a;printf()、scanf()、fprintf()、fscanf()、spri…...

【k8s】创建基于sa的token的kubeconfig

需求 创建一个基于sa的token的kubeconfig文件&#xff0c;并用这个文件来访问集群。 具体创建sa 和sa的token请参考文章: 【k8s】给ServiceAccount 创建关联的 Secrets-CSDN博客 创建sa apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata:namespace: jtkjdevnam…...

Gentoo Linux部署LNMP

一、安装nginx 1.gentoo-chxf ~ # emerge -av nginx 提示配置文件需更新 2.gentoo-chxf ~ # etc-update 3.gentoo-chxf ~ # emerge -av nginx 4.查看并启动nginx gentoo-chxf ~ # systemctl status nginx gentoo-chxf ~ # systemctl start nginx gentoo-chxf ~ # syst…...

2411C++,CXImage简单使用

介绍 CxImage是一个可非常简单快速的加载,保存,显示和转换图像的C类. 文件格式和链接的C库 Cximage对象基本上是加了一些成员变量来保存有用信息的一个位图: class CxImage{...protected:void* pDib; //包含标题,调色板,像素BITMAPINFOHEADER head; //标准头文件CXIMAGEINFO…...

什么是 Kubernetes(K8s)?

什么是 Kubernetes&#xff08;K8s&#xff09;&#xff1f; Kubernetes&#xff08;简称 K8s&#xff09; 是一个用来管理容器的开源工具&#xff0c;它可以自动化部署、扩展和管理容器化应用。简单来说&#xff0c;K8s 就是一个“容器管家”&#xff0c;负责确保你的应用程序…...

深入解析:TypeScript 与 Vue 的完美结合

文章目录 前言一、准备工作二、基本用法三、进阶主题结语 前言 Vue.js 是一款流行的渐进式 JavaScript 框架&#xff0c;它以易于学习和灵活的特性而闻名。TypeScript 则是 JavaScript 的一个超集&#xff0c;它引入了静态类型检查等高级功能&#xff0c;有助于构建更大型且复…...

机器学习周志华学习笔记-第13章<半监督学习>

机器学习周志华学习笔记-第13章&#xff1c;半监督学习&#xff1e; 卷王&#xff0c;请看目录 13半监督学习13.1 生成式方法13.2 半监督SVM13.3 基于分歧的方法13.4 半监督聚类 13半监督学习 前面我们一直围绕的都是监督学习与无监督学习&#xff0c;监督学习指的是训练样本包…...

软件工程——期末复习(1)

名词解释&#xff1a; 名词解释--人月 答案&#xff1a;人月是软件开发工作量的单位&#xff0c;1人月表示1个程序员1个月的工作时间所开发的代码量。 请解释软件缺陷、错误和失败&#xff0c;并简单举例说明。 答案&#xff1a;缺陷&#xff08;defect&#xff09;指系统代…...

【JavaEE初阶 — 网络编程】实现基于TCP协议的Echo服务

TCP流套接字编程 1. TCP &#xff06; UDP 的区别 TCP 的核心特点是面向字节流&#xff0c;读写数据的基本单位是字节 byte 2 API介绍 2.1 ServerSocket 定义 ServerSocket 是创建 TCP 服务端 Socket 的API。 构造方法 方法签名 方法说明 ServerS…...

vue结合canvas动态生成水印效果

在 Vue 项目中添加水印可以通过以下几种方式实现&#xff1a; 方法一&#xff1a;使用 CSS 直接通过 CSS 的 background 属性实现水印&#xff1a; 实现步骤 在需要添加水印的容器中设置背景。使用 rgba 设置透明度&#xff0c;并通过 background-repeat 和 background-size…...

Qt 5 中的 QTextStream 使用指南

文章目录 Qt 5 中的 QTextStream 使用指南介绍基本概念读取文件注意事项结论 Qt 5 中的 QTextStream 使用指南 介绍 QTextStream 是 Qt 框架中用于处理文本数据的类。它提供了方便的接口来读写文本文件或字符串&#xff0c;支持多种编码格式&#xff0c;并且可以与 QIODevice…...

中安证件OCR识别技术助力鸿蒙生态:智能化证件识别新体验

在数字化和智能化的浪潮中&#xff0c;伴随国产化战略的深入推进&#xff0c;国产操作系统和软件生态的建设逐渐走向成熟。鸿蒙操作系统&#xff08;HarmonyOS Next&#xff09;作为华为推出的重要操作系统&#xff0c;凭借其开放、灵活和高效的特点&#xff0c;正在加速在多个…...

SpringBoot 框架下基于 MVC 的高校办公室行政事务管理系统:设计开发全解析

2系统开发环境 2.1vue技术 Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 [5] 与其它大型框架不同的是&#xff0c;Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;还便于与第…...

【ArkTS】使用AVRecorder录制音频 --内附录音机开发详细代码

系列文章目录 【ArkTS】关于ForEach的第三个参数键值 【ArkTS】“一篇带你读懂ForEach和LazyForEach” 【小白拓展】 【ArkTS】“一篇带你掌握TaskPool与Worker两种多线程并发方案” 【ArkTS】 一篇带你掌握“语音转文字技术” --内附详细代码 【ArkTS】技能提高–“用户授权”…...

Selenium3+Python如何操作键盘

selenium操作键盘&#xff0c;需要导入Keys类&#xff1a;“from selenium.webdriver.common.keys import Keys” 调用键盘操作的快捷键的方法 &#xff1a; 单键值&#xff1a;直接传入对应的键值“element.send_keys”(快捷键的键值) 组合键&#xff1a;键值之间由逗号分隔…...

PLC协议

PLC协议通常指的是可编程逻辑控制器&#xff08;Programmable Logic Controller, PLC&#xff09;与其他设备之间通信时所使用的协议。PLC广泛应用于工业自动化领域&#xff0c;用于控制和监控设备。不同厂商和应用场景可能使用不同的通信协议。 常见的PLC通信协议 1. Modbus …...

C_字符串的一些函数

1.字符串输入函数 scanf("%s",数组名)&#xff1b; gets(数组名)&#xff1b; 区别&#xff1a; scanf(“%s”,数组名); 把空格识别为输入结束 #include <stdio.h>int main() {char a[10];printf("输入&#xff1a;");scanf("%s",a)…...

使用Native AOT发布C# dll 提供给C++调用

Native AOT&#xff0c;即提前本地编译&#xff08;Ahead-Of-Time Compilation&#xff09;&#xff0c;是一种将托管代码&#xff08;如 C#&#xff09;编译为本机可执行文件的技术&#xff0c;无需在运行时进行任何代码生成。 &#xff08;Native AOT 优缺点截图摘自张善友博…...

Git 提交代码日志信息

前言 在项目中经常用到git提交代码&#xff0c;每次提交时需要添加日志信息&#xff0c;那么一套规范的日志信息会让整个git仓库看起来赏心悦目&#xff01; 以下是Git 提交代码日志信息的建议&#xff1a; 一、格式规范 标题&#xff08;Subject&#xff09; 标题是日志信息中…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

centos 7 部署awstats 网站访问检测

一、基础环境准备&#xff08;两种安装方式都要做&#xff09; bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats&#xff0…...

【位运算】消失的两个数字(hard)

消失的两个数字&#xff08;hard&#xff09; 题⽬描述&#xff1a;解法&#xff08;位运算&#xff09;&#xff1a;Java 算法代码&#xff1a;更简便代码 题⽬链接&#xff1a;⾯试题 17.19. 消失的两个数字 题⽬描述&#xff1a; 给定⼀个数组&#xff0c;包含从 1 到 N 所有…...

系统设计 --- MongoDB亿级数据查询优化策略

系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log&#xff0c;共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题&#xff0c;不能使用ELK只能使用…...

基于Docker Compose部署Java微服务项目

一. 创建根项目 根项目&#xff08;父项目&#xff09;主要用于依赖管理 一些需要注意的点&#xff1a; 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件&#xff0c;否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

让AI看见世界:MCP协议与服务器的工作原理

让AI看见世界&#xff1a;MCP协议与服务器的工作原理 MCP&#xff08;Model Context Protocol&#xff09;是一种创新的通信协议&#xff0c;旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天&#xff0c;MCP正成为连接AI与现实世界的重要桥梁。…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

排序算法总结(C++)

目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指&#xff1a;同样大小的样本 **&#xff08;同样大小的数据&#xff09;**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...