JVM规范学习总结-JVM规范基本概念

JVM规范基本概念

  • 前言
  • [从系统工程师角度学习 JVMS:Java 源码、Class 文件、JVM 执行引擎与本地机器码](#从系统工程师角度学习 JVMS:Java 源码、Class 文件、JVM 执行引擎与本地机器码)
    • 一、学习目标与核心结论
    • [Java 源码(.java)](#Java 源码(.java))
    • [Class 文件(.class)](#Class 文件(.class))
    • [JVM 运行时](#JVM 运行时)
    • [CPU + 操作系统 + 硬件资源](#CPU + 操作系统 + 硬件资源)
    • 二、理解四个核心概念及其边界
      • [1. Java 源码:描述程序的语言级行为](#1. Java 源码:描述程序的语言级行为)
      • [2. Class 文件:Java 编译器与 JVM 之间的二进制接口](#2. Class 文件:Java 编译器与 JVM 之间的二进制接口)
      • [3. JVM 执行引擎:负责实现字节码规定的语义](#3. JVM 执行引擎:负责实现字节码规定的语义)
      • [4. 本地机器码:最终由处理器执行的指令](#4. 本地机器码:最终由处理器执行的指令)
    • [三、结合 Java 源码,完整追踪一次编译与执行](#三、结合 Java 源码,完整追踪一次编译与执行)
      • [1. Java 源码:`AddDemo.java`](#1. Java 源码:AddDemo.java)
      • [2. 编译为 Class 文件](#2. 编译为 Class 文件)
      • [3. 使用 `javap` 检查字节码](#3. 使用 javap 检查字节码)
    • [四、JVM 如何从 Class 文件进入执行引擎](#四、JVM 如何从 Class 文件进入执行引擎)
      • [1. 类加载:把二进制定义引入 JVM](#1. 类加载:把二进制定义引入 JVM)
      • [2. 运行时数据区:字节码需要的执行环境](#2. 运行时数据区:字节码需要的执行环境)
      • [3. 解释执行与 JIT 编译:两条可以协作的执行路径](#3. 解释执行与 JIT 编译:两条可以协作的执行路径)
    • [五、结合 OpenJDK 源码理解各层职责](#五、结合 OpenJDK 源码理解各层职责)
      • [1. Class 文件解析:`classFileParser.cpp`](#1. Class 文件解析:classFileParser.cpp)
      • [2. 解释器:`templateInterpreter.cpp`](#2. 解释器:templateInterpreter.cpp)
      • [3. JIT 编译:从字节码语义到机器指令](#3. JIT 编译:从字节码语义到机器指令)
    • 六、如何在实际环境验证这条链路
      • 第一步:查看编译产物
      • [第二步:禁用 JIT,观察解释执行](#第二步:禁用 JIT,观察解释执行)
      • [第三步:查看 JIT 编译事件](#第三步:查看 JIT 编译事件)
    • 七、从系统工程师视角形成最终学习总结

前言

本文旨在记录近期研读Java源码的学习心得与疑难问题。由于个人理解水平有限,文中内容难免存在疏漏,恳请读者不吝指正。

从系统工程师角度学习 JVMS:Java 源码、Class 文件、JVM 执行引擎与本地机器码

一、学习目标与核心结论

学习《Java 虚拟机规范》(JVMS, Java Virtual Machine Specification),不能只停留在理解 Java 代码如何运行,而应建立从编译器、二进制文件、虚拟机运行时到 CPU 指令执行的完整技术链路。

本文以 Java SE 26 版 JVMS 为主要规范依据,结合 OpenJDK/HotSpot 实现源码和可运行示例进行分析。JVMS 是针对抽象虚拟机的规范,并不规定 JVM 必须采用哪种内部实现;解释执行、JIT 编译、机器码生成等实现策略,可以在满足规范语义的前提下由虚拟机实现者决定。

学习过程中需要始终区分两个层次:

  • 规范层:规定 Class 文件的格式、字节码指令的语义、运行时数据区、方法调用和异常处理等行为。
  • 实现层:研究 HotSpot 如何解析 Class 文件、执行字节码、编译热点方法、生成机器码,以及如何协调操作系统和 CPU。

核心链路如下:

Java 源码(.java)

开发者编写的高级语言程序

javac:词法、语法、类型检查等编译工作

Class 文件(.class)

平台无关的二进制结构、常量池、方法字节码及属性等

类加载、验证、链接、初始化;解释执行或编译执行

JVM 运行时

解释器

按字节码语义执行

JIT 编译器

将热点代码编译为机器码

两条路径可以共存,并非所有方法都会经历完全相同的执行流程。

机器指令在具体处理器上执行

CPU + 操作系统 + 硬件资源

执行本地指令、访问内存、处理分支和调用等

需要特别注意:这是一张逻辑关系图,不表示每个 Java 程序都必须依次经过所有阶段。JVMS 明确允许实现者在加载时或执行期间将字节码转换为宿主 CPU 的指令,也允许采用其他实现方式。

二、理解四个核心概念及其边界

1. Java 源码:描述程序的语言级行为

Java 源码由开发者编写,例如:

java 复制代码
int result = add(20, 22);

这段代码描述的是高级语言操作,不直接描述 CPU 寄存器、机器指令编码或调用约定。

通常,javac 将 Java 源文件编译为 JVM 能够识别的 Class 文件。编译器会进行语法和类型检查,并生成适合目标 Class 文件版本的二进制结构。

从系统工程师角度,需要关注三个问题:

  • 语义:程序应该产生什么结果?这由 Java 语言规范及相关 API 契约约束。
  • 编译产物:源码中的一个操作会被编译成哪些 JVM 字节码?
  • 运行时优化:JVM 后续是否会内联方法、消除冗余计算或者改变机器码布局?

不能仅凭源码推断最后执行了哪些 CPU 指令。

2. Class 文件:Java 编译器与 JVM 之间的二进制接口

Class 文件是理解 JVMS 最关键的中间层。

JVMS 第 4 章规定了 Class 文件结构。它采用与具体硬件和操作系统无关的二进制格式,文件中的多字节数据按大端序存储;一个 Class 文件包含一个类、接口或模块的定义。类也可以由类加载器动态生成,并不一定来自磁盘上的 .class 文件。

一个普通的 Class 文件主要包含以下部分:

部分 主要职责 系统分析重点
magic 标识 Class 文件格式,值为 0xCAFEBABE 文件是否具有正确格式
minor_version、major_version 声明 Class 文件版本 目标 JVM 是否支持该版本
constant_pool 存储类、方法、字段、字符串等常量和符号引用 常量解析、动态链接
access_flags 描述类的访问及特定属性 类定义的元信息
fields 描述字段 类型、名称、访问标志
methods 描述方法 方法签名、访问标志、代码属性
attributes 存放代码及附加元数据 Code、StackMapTable、调试信息等

该布局和字段定义来自 JVMS 第 4 章。

其中最值得关注的是 Code 属性。对于具有普通 Java 方法体的方法,它保存 JVM 字节码以及执行所需的辅助信息,包括:

  • max_stack:方法执行过程中操作数栈所需的最大深度。
  • max_locals:方法局部变量表所需的槽位数量。
  • code:方法的字节码指令序列。
  • exception_table:异常处理表。
  • attributes:例如栈映射帧、行号等附加信息。

抽象结构可以简化为:

复制代码
ClassFile
 ├── magic / version
 ├── constant_pool
 ├── access_flags / this_class / super_class
 ├── fields[]
 ├── methods[]
 │    ├── method_info
 │    └── Code
 │         ├── max_stack
 │         ├── max_locals
 │         ├── code[]
 │         ├── exception_table[]
 │         └── attributes[]
 └── attributes[]

学习总结:Class 文件不是 Java 源码的简单压缩版,也不是 CPU 机器码。它是具有严格格式和语义约束的 JVM 二进制接口。

这也解释了为什么不同语言编译器可以生成 JVM 字节码:JVM 关注的是符合规范的 Class 文件及其语义,而不是程序最初由哪一种高级语言编写。

3. JVM 执行引擎:负责实现字节码规定的语义

JVMS 描述的是一台抽象虚拟机。它规定程序执行结果必须满足什么语义,但不会要求每个实现都使用同一种解释器、编译器或内存布局。

在 HotSpot 中,可以重点区分以下几个组成部分。

组成部分 职责 关键问题
类加载和链接机制 读取、验证、准备并解析类 非法 Class 文件如何被发现?
运行时数据区 为执行提供栈、堆、常量池等运行时资源 对象和方法执行状态在哪里?
解释器 解释执行 JVM 字节码 指令如何被分派和执行?
JIT 编译器 将热点方法或代码片段编译成本地代码 如何利用运行时信息优化?
运行时支持机制 提供对象分配、异常处理、GC、同步和运行时调用等支持 编译代码怎样正确参与 JVM 运行?

注意:这些是帮助分析 HotSpot 的实现划分,不应理解为 JVMS 要求所有 JVM 都必须具有完全相同的软件组件。

理解执行引擎时,有一个容易忽略的细节:

解释执行并不意味着 CPU 直接执行 JVM 字节码。

JVM 字节码是一套面向抽象虚拟机的指令集,而 CPU 执行的是当前处理器架构定义的机器指令。HotSpot 的解释器本身也是由宿主 CPU 可以执行的本地代码实现的,它根据当前字节码执行相应的处理逻辑。相关实现可以从 OpenJDK 的 templateInterpreter.cpp 入手。

4. 本地机器码:最终由处理器执行的指令

本地机器码(native machine code)是面向具体处理器架构生成的指令序列,例如 x86-64 或 AArch64。

它和 JVM 字节码不是同一种指令集。

假设 JVM 字节码中有:

复制代码
iload_0
iload_1
iadd
ireturn

这描述了 JVM 抽象执行过程:取得两个整型操作数、相加并返回结果。

JIT 编译器可能将其转换成类似于以下的处理器级操作:

复制代码
; 示意性伪汇编,不对应某个确定的 JVM 编译结果

; 将两个整数参数放入处理器寄存器
; 使用整数加法指令执行相加
; 按当前平台的调用约定返回结果

具体的机器指令、寄存器分配、参数传递、栈帧和返回约定,取决于目标架构、操作系统、编译优化和调用场景,不能仅凭字节码固定下来。

而且,JIT 不要求保持字节码与机器指令的一一对应关系。编译器可能内联方法、消除重复计算、合并操作或者把中间结果一直保存在寄存器中。

因此,排查性能问题时,必须区分:

  1. 字节码层:编译器输出的 JVM 指令是什么?
  2. JVM 实现层:解释器或 JIT 如何处理这些指令?
  3. 硬件执行层:实际生成了什么机器指令,指令如何影响寄存器、缓存和内存访问?

三层观察的是同一个程序在不同抽象层次上的表现。

三、结合 Java 源码,完整追踪一次编译与执行

下面使用一个简单示例,观察源代码如何变成字节码,再分析 JVM 如何执行它。

1. Java 源码:AddDemo.java

java 复制代码
public final class AddDemo {

    // 定义一个静态方法。
    // 在 Java 源码层面,它接受两个 int 参数,并返回它们的和。
    static int add(int a, int b) {
        return a + b;
        // 注意:这里写的是 Java 加法表达式,
        // 并没有指定必须使用哪条 CPU 加法指令。
    }

    public static void main(String[] args) {

        // 调用 add 方法。
        // javac 通常会将该调用编译为 invokestatic 字节码。
        int result = add(20, 22);

        // 获取标准输出对象并调用 println。
        // 字节码层面通常涉及 getstatic、iload 和 invokevirtual。
        System.out.println(result);
    }
}

从源码角度,这段程序只表达了两个整型相加并打印结果。它没有声明 CPU 寄存器、指令地址或本地调用约定。

2. 编译为 Class 文件

执行:

shell 复制代码
javac -g AddDemo.java

生成 AddDemo.class。

其中:

  • javac 负责将源码编译为 JVM 可识别的 Class 文件。
  • -g 请求生成调试信息,便于查看源码行号和局部变量信息。
  • 生成的字节码仍然不是针对 x86-64 或 AArch64 的 CPU 指令。

3. 使用 javap 检查字节码

执行:

shell 复制代码
javap -c -v -p AddDemo

其中 -c 用于反汇编方法字节码,-v 用于查看详细 Class 文件信息,-p 用于显示包括私有成员在内的类成员。

add 方法的关键输出通常类似于:

复制代码
static int add(int, int);
  Code:
     0: iload_0
     1: iload_1
     2: iadd
     3: ireturn

逐条分析:

偏移 字节码 含义
0 iload_0 将第 0 个局部变量中的整型值压入操作数栈
1 iload_1 将第 1 个局部变量中的整型值压入操作数栈
2 iadd 弹出两个整型操作数并将和压入操作数栈
3 ireturn 返回整型结果

这是对 JVM 抽象执行语义的描述,而不是对物理寄存器操作的直接描述。iload、iadd 与 ireturn 的语义由 JVMS 指令集章节定义。

main 方法的关键指令通常类似于:

复制代码
0:  bipush        20
2:  bipush        22
4:  invokestatic  #...  // Method add:(II)I
7:  istore_1
8:  getstatic     #...  // Field java/lang/System.out
11: iload_1
12: invokevirtual #...  // Method java/io/PrintStream.println:(I)V
15: return

这里的 #... 只是示意,实际的常量池索引由编译结果决定。

重要指令说明:

  • bipush:将一个带符号字节表示的立即数扩展为整数并压入操作数栈。
  • invokestatic:通过方法符号引用调用静态方法。
  • istore_1:把结果写入局部变量表的第 1 个槽位。
  • getstatic:读取静态字段,这里是 System.out。
  • invokevirtual:执行实例方法调用,这里用于调用 println。
  • return:从返回类型为 void 的方法正常返回。

关键结论:Java 源码里的方法调用,到 Class 文件中表现为 JVM 的方法调用指令和符号引用。符号引用解析、目标方法选择以及最终的底层调用方式,是后续运行时处理的问题。

需要注意,以上输出是用于理解机制的典型形式;实际指令细节应以当前 JDK 编译得到的 Class 文件为准。

四、JVM 如何从 Class 文件进入执行引擎

从系统工程师角度,理解程序运行过程时,应当把类加载与链接、运行时数据管理、字节码执行和机器码生成分开分析。

1. 类加载:把二进制定义引入 JVM

典型流程可以抽象为:

复制代码
读取 Class 文件或其他字节来源
          │
          ▼
      加载(Loading)
          │
          ▼
      链接(Linking)
       ├─ 验证(Verification)
       ├─ 准备(Preparation)
       └─ 解析(Resolution)
          │
          ▼
      初始化(Initialization)
          │
          ▼
      方法执行

其中,链接包含验证、准备和解析。解析的具体时机允许采用不同策略,并不意味着所有符号引用都必须在类刚加载时一次性解析完成。

从排障视角,需要分清典型问题所属的阶段:

问题 重点排查方向
ClassFormatError Class 文件格式、版本或结构
VerifyError 字节码约束、类型安全及验证规则
NoClassDefFoundError 类定义的可用性,以及此前加载或初始化失败的情况
NoSuchMethodError 方法符号引用与运行时类定义是否兼容
ExceptionInInitializerError 类初始化过程中的异常

这些异常并不都由同一个组件抛出,但把错误定位到正确的阶段,可以明显缩小排查范围。

2. 运行时数据区:字节码需要的执行环境

JVMS 第 2 章还规定了抽象运行时数据区。学习时,应特别关注以下结构:

运行时结构 主要作用 系统工程师需要理解什么
pc 寄存器 跟踪当前线程正在执行的 JVM 指令位置 字节码执行位置及调用返回
JVM 栈 管理方法调用帧 调用深度、栈帧和局部变量
局部变量表 保存方法参数及局部变量槽位 参数传递、变量生命周期
操作数栈 为字节码提供操作数和中间计算结果 iadd 等指令如何消费与产生数据
堆 为对象及数组提供运行时存储空间 对象布局、GC、分配与内存访问
方法区 保存类相关的运行时结构 类元数据与实现相关的存储方式
运行时常量池 支持常量及符号引用等信息 字段、方法引用和动态链接
本地方法栈 为本地方法执行提供相关运行时支持 JNI、线程与本地运行环境

这些名称描述的是 JVMS 的抽象模型。不能简单地把规范中的每个结构等同于 HotSpot 中某个固定的内存地址、C++ 类或物理内存分区。

例如,解释器执行 iadd 时,JVMS 的语义可以描述为从操作数栈取得两个整数并压入计算结果;JIT 编译后的代码则可能直接利用 CPU 寄存器完成运算,未必真的在物理内存中构造一个与抽象操作数栈逐项对应的结构。

学习总结:规范定义的是可观察的行为和必须满足的约束,实现可以采用不同的数据结构与优化方式,只要保持规定的语义。

3. 解释执行与 JIT 编译:两条可以协作的执行路径

在常见的 HotSpot 分层编译模式下,程序可能经历以下过程:

复制代码
            Class 文件
                │
                ▼
          类加载与链接
                │
                ▼
            方法执行
                │
          ┌─────┴─────┐
          ▼           ▼
       解释执行     运行时编译
          │           │
          │       收集运行信息
          │           │
          │       C1 / C2 编译
          │           │
          └─────┬─────┘
                ▼
          编译机器码执行
                │
                ▼
       运行时监测及必要的去优化

这是一种常见的实现路径,不是所有 JVM 都必须遵循的固定流程。

解释执行:解释器读取字节码并执行相应操作。它的指令处理逻辑本身也是由宿主机器指令实现的。

JIT 编译:编译器利用静态信息和运行时收集的信息,优化热点方法或循环,并生成适用于目标处理器的本地机器码。

去优化(Deoptimization):当编译时依赖的某些假设不再成立,或者运行时需要恢复更适合解释执行的状态时,JVM 可以使执行从已编译代码回到解释器等适当执行状态。

因此,不应把"一次方法执行"简单理解为"先解释完毕,再完整编译一次"。在真实的 JVM 中,同一方法的执行路径可能随运行时状态而变化。

五、结合 OpenJDK 源码理解各层职责

下面列出适合从源码入手的几个关键位置。阅读时,应当区分 JVMS 的强制语义要求与 OpenJDK/HotSpot 自己选择的实现方式。

1. Class 文件解析:classFileParser.cpp

源码位置:src/hotspot/share/classfile/classFileParser.cpp

OpenJDK 在解析 Class 文件时,需要检查并处理二进制结构,读取常量池、字段、方法以及相关属性。

源码中的部分定义如下,右侧注释为学习说明:

cpp 复制代码
#define JAVA_CLASSFILE_MAGIC 0xCAFEBABE
// 学习点:Class 文件以固定魔数标识其文件格式。

#define JAVA_MIN_SUPPORTED_VERSION 45
// 学习点:这是该源码版本中使用的最低支持版本定义。
// 实际支持范围应以正在分析的 JDK 版本和实现配置为准。

上述定义可以在 OpenJDK 的 classFileParser.cpp 中找到。

阅读该文件时,重点追踪:

  1. Class 文件字节流是如何读取的。
  2. 常量池中的符号与引用信息是如何解析的。
  3. 字段和方法的元数据如何构建。
  4. Code、StackMapTable 等属性如何参与类定义处理。
  5. 解析和格式检查与后续字节码验证之间有什么区别。

需要注意,完整的验证流程不仅涉及 ClassFileParser,还需要结合 HotSpot 的验证器实现和 JVMS 第 4 章的约束一起分析。

2. 解释器:templateInterpreter.cpp

源码位置:src/hotspot/share/interpreter/templateInterpreter.cpp

该文件可以帮助理解 HotSpot 如何初始化解释器、生成解释器代码以及设置字节码分派相关的数据结构。

以该文件中的初始化过程为例,其关键步骤可以概括为:

cpp 复制代码
// 教学性摘录:省略非关键实现细节。

AbstractInterpreter::initialize();
// 注释:初始化解释器相关的基础结构。

TemplateTable::initialize();
// 注释:初始化模板解释器使用的字节码处理模板。

// 后续由解释器生成器生成相应解释器代码。

_active_table = _normal_table;
// 注释:选择正常执行使用的字节码分派表。

这段摘录用于指出源码阅读的方向,不是完整可编译的独立代码。实际的代码生成过程应以具体 JDK 版本的实现为准。

从这里要建立的认识是:

HotSpot 解释器不是简单地把每个字节码当作一段独立的 CPU 指令执行,而是通过本地代码中的指令处理和分派逻辑来实现 JVM 字节码的语义。

3. JIT 编译:从字节码语义到机器指令

HotSpot 中可以重点阅读:

源码位置 阅读重点
src/hotspot/share/compiler/compileBroker.cpp 编译请求与编译任务的协调
src/hotspot/share/c1/ C1 编译器实现
src/hotspot/share/opto/compile.cpp C2 编译流程与优化相关逻辑
src/hotspot/share/opto/output.cpp C2 编译结果的代码生成与输出相关逻辑

研究时建议按照这条主线追踪:

复制代码
编译请求
   ↓
编译器分析方法
   ↓
构建并优化中间表示
   ↓
指令选择和寄存器分配
   ↓
生成目标架构机器码
   ↓
纳入运行时可执行代码的管理

这是帮助理解编译过程的逻辑图,并不代表每个 HotSpot 编译器使用完全一样的内部流水线。

学习时要重点观察:

  • 哪些信息来自 Class 文件,哪些来自运行时 profile。
  • 字节码经过何种分析后被转换为内部表示。
  • 内联、常量传播、死代码消除等优化如何改变生成代码。
  • 目标 CPU 的指令选择及寄存器分配如何影响最终结果。
  • 编译代码如何与异常处理、GC、安全点和去优化机制协作。

对系统工程师而言,最重要的不是机械背诵所有编译器类名,而是掌握从字节码语义到实际机器指令之间的转换和优化过程。

六、如何在实际环境验证这条链路

建议在本地安装的 JDK 上依次执行下面的操作。

第一步:查看编译产物

shell 复制代码
javac -g AddDemo.java
javap -c -v -p AddDemo

观察常量池、方法信息、Code 属性和字节码指令。不要只看反汇编结果中的指令名称,还要结合偏移和操作数栈语义理解。

第二步:禁用 JIT,观察解释执行

shell 复制代码
java -Xint AddDemo

对于普通 Java 方法,-Xint 可用于观察解释执行路径。它并不意味着 JVM 及其所调用的本地库不执行机器码。

第三步:查看 JIT 编译事件

shell 复制代码
java -XX:+PrintCompilation AddDemo

PrintCompilation 用于观察编译事件。简单示例可能不会触发 AddDemo 中方法的 JIT 编译,因为执行次数不足以使其成为热点。

若要进一步验证 JIT,可以修改程序,使 add 在长循环中被反复调用,再观察 PrintCompilation 的输出。具体是否编译、何时编译以及最终生成何种代码,都受编译策略、运行时数据和 JVM 参数影响。

如果希望观察机器指令级结果,还可以研究适用于目标 JDK 的汇编打印和反汇编工具。需要明确的是,javap -c 输出的是 JVM 字节码,不是 JIT 生成的 CPU 机器码。汇编输出工具及其可用性可能依赖 JVM 构建、诊断选项和相应反汇编支持。

七、从系统工程师视角形成最终学习总结

通过上述内容,应当形成以下认识。

第一,Java 源码和 Class 文件是不同的抽象层。 源码描述程序的语言级意图,Class 文件以严格的二进制格式表达类结构和 JVM 字节码。Class 文件版本、常量池、方法描述符和属性,是研究编译产物与运行时行为的基础。

第二,JVMS 规定语义,而不是规定唯一实现。 同一组字节码可以由不同 JVM 实现执行。解释器、JIT、对象布局、垃圾回收策略以及具体的机器码生成方式,都可以存在实现差异,但必须保持规范要求的行为。

第三,JVM 字节码不是 CPU 机器码。 字节码定义抽象执行操作;解释器使用本地代码处理这些操作,JIT 则可以将热点代码转换成针对目标 CPU 的机器指令。两者都最终依赖宿主硬件执行本地指令。

第四,性能分析必须跨层验证。 javap 可以分析字节码,但不能直接证明最终生成了哪些机器指令。解释器源码可以解释字节码分派的实现,编译器源码可以解释优化与代码生成,而机器码观测则用于进一步验证寄存器、指令序列和调用路径。只有综合这些层次,才能分析方法内联、运行时优化及硬件执行成本。

第五,正确的研究方法是规范与实现对照。 建议先掌握 JVMS 第 2 章的运行时结构、第 4 章的 Class 文件格式、第 5 章的加载与链接,以及第 6 章的指令语义;再结合 OpenJDK 的类文件解析器、解释器和 JIT 编译器逐层追踪。

最终要建立的核心模型是:

Java 源码描述程序意图,Class 文件定义 JVM 可以识别的程序表示,JVMS 规定其抽象执行语义,而具体 JVM 通过解释执行、JIT 编译及运行时支持机制,将这些语义落实到宿主机器的实际执行过程。

相关推荐
进击的荆棘1 小时前
Linux系统——进程间通信之system V
linux·共享内存·system v
Demon--hx2 小时前
jsoncpp 核心概念梳理:命名空间、Value 容器与格式化输出
c++
时间静止不是简史5 小时前
生产事故排查:Redis 宕机导致补偿队列消费线程死亡,通话录音未上送业务平台
java·redis
2301_32241428048 小时前
基于SpringBoot+Vue的休闲零食超市管理系统的设计与实现59004-计算机毕设 原创(免费领源码+部署教程+开发环境)
java·vue.js·spring boot·redis·mysql·决策树·推荐算法
金銀銅鐵10 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
福建佰胜张工10 小时前
SMC 薄型气爪 MHF2-16D1 深度解析:平行开闭、低剖面结构在自动化装配中的选型与落地
java·服务器·安全·自动化
catoop10 小时前
API Key 设计与安全生成方案:结构拆解、数据库设计与 Java 实现
java·数据库·安全
system_error_x11 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
驭渊的小故事11 小时前
Spring AI Alibaba 实战:从maven依赖治理到声明式工具调用
java·人工智能·spring