当前位置: 首页 > 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; 标题是日志信息中…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

23-Oracle 23 ai 区块链表(Blockchain Table)

小伙伴有没有在金融强合规的领域中遇见&#xff0c;必须要保持数据不可变&#xff0c;管理员都无法修改和留痕的要求。比如医疗的电子病历中&#xff0c;影像检查检验结果不可篡改行的&#xff0c;药品追溯过程中数据只可插入无法删除的特性需求&#xff1b;登录日志、修改日志…...

Python爬虫实战:研究feedparser库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...

STM32F4基本定时器使用和原理详解

STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)

UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中&#xff0c;UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化&#xf…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...

MyBatis中关于缓存的理解

MyBatis缓存 MyBatis系统当中默认定义两级缓存&#xff1a;一级缓存、二级缓存 默认情况下&#xff0c;只有一级缓存开启&#xff08;sqlSession级别的缓存&#xff09;二级缓存需要手动开启配置&#xff0c;需要局域namespace级别的缓存 一级缓存&#xff08;本地缓存&#…...