Linux 系统的内存分布结构及其之间的关系(持续更新)

Linux 系统的内存分布结构及其之间的关系(持续更新)

Linux 系统的内存分布结构(memory layout / memory organization)是理解操作系统内核、驱动、应用程序内存管理的基础之一。下面将从宏观到微观、从物理内存到虚拟内存的角度,系统地梳理整个结构。


一、整体框架:物理内存 vs 虚拟内存

类型说明典型范围(x86_64)
物理内存(Physical Memory)实际存在的内存条上的存储空间0x0000_0000 ~ 物理RAM最大地址
虚拟内存(Virtual Memory)每个进程或内核看到的逻辑地址空间,由MMU映射到物理内存用户态通常 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff

Linux 中每个进程看到的虚拟内存空间都是独立的,通过 页表(Page Table) 映射到共享的物理内存。


二、Linux 内核视角下的内存布局

(1)物理内存布局

在 Linux 启动后,物理内存被划分为以下几个区域(在 /proc/zoneinfo 可以看到):

区域名作用对应体系结构
ZONE_DMA旧式设备需要的低端物理内存(<16MB)x86等老平台
ZONE_DMA32需要 32 位地址的 DMA 设备使用(<4GB)x86_64平台
ZONE_NORMAL普通内存区,内核直接映射通常从 4GB 开始
ZONE_HIGHMEM高端内存,内核需要临时映射才能访问(32位系统)仅32位平台
在 64 位 Linux 系统上,通常没有 HIGHMEM,因为虚拟地址空间够大,全部物理内存都可以直接映射。

(2)虚拟地址空间布局(内核空间)

Linux 内核的虚拟地址空间分为:

区域作用典型地址(x86_64)
内核空间 (kernel space)共享于所有进程,由内核使用ffff800000000000 ~ ffffffffffffffff
直接映射区 (direct mapping region)将所有物理内存映射到虚拟空间通常 ffff888000000000 开始
vmalloc 区动态分配非连续物理内存的虚拟区域ffffc90000000000 ~ ffffe8ffffffffff
模块加载区 (module region)内核模块加载的虚拟地址ffffffffa0000000
fixmap 区固定映射的一些特殊页(如APIC、IO空间)高端地址附近

三、用户进程的虚拟内存布局

每个用户进程的虚拟地址空间大致如下(可通过 /proc/<pid>/maps 查看):

+--------------------------+ 高地址 | stack (栈区) | <-- 向下增长 +--------------------------+ | mmap() 映射区 | | (共享库、匿名映射等) | +--------------------------+ | heap (堆区) | <-- malloc/brk 向上增长 +--------------------------+ | data 段 (已初始化全局变量) | +--------------------------+ | bss 段 (未初始化全局变量) | +--------------------------+ | text 段 (代码段、只读区) | +--------------------------+ | NULL (未映射区) | +--------------------------+ 低地址 
用户空间和内核空间之间通常以 TASK_SIZE 分界,比如:32位系统:TASK_SIZE = 0xC0000000(3GB用户 + 1GB内核)64位系统:用户空间最大约 128TB 左右(取决于架构)

四、页表与地址转换

CPU 通过 MMU(内存管理单元) 把虚拟地址转换为物理地址。Linux 使用 多级页表结构(4级或5级):

虚拟地址 ↓ PGD → P4D → PUD → PMD → PTE → 物理页帧 

每一级页表指向下一层的页表基址。每个页的典型大小:

  • 普通页:4KB
  • 大页(HugePage):2MB 或 1GB

五、查看与分析命令

命令用途
cat /proc/meminfo系统内存总览
cat /proc/zoneinfo内存分区(ZONE)详情
cat /proc/iomem物理内存映射
free -h查看系统内存使用
vmstat, top, htop动态查看内存
pmap <pid>查看进程虚拟内存分布
cat /proc/<pid>/maps进程内存映射详情

六、简化示意图(x86_64)

物理内存: +-------------------------+ | BIOS/设备保留区 | < 1MB +-------------------------+ | DMA区 (ZONE_DMA) | < 16MB +-------------------------+ | DMA32区 (ZONE_DMA32) | < 4GB +-------------------------+ | 普通区 (ZONE_NORMAL) | > 4GB +-------------------------+ 内核虚拟地址空间: ffff800000000000 ─────────────── │ fixmap, modules, vmalloc │ │ direct mapping of all RAM │ │ 内核页表、堆栈、代码、数据等 │ ─────────────────────────────── 0000000000000000 ─────────────── │ 用户空间 (text, data, heap, │ │ stack, mmap, libc, etc.) │ ─────────────────────────────── 

这三个概念之间确实容易混淆,但它们其实是**“同一个内存系统在不同抽象层次上的三种视角”**。


七、三者的逻辑关系(由底向上)

物理内存(Physical Memory) ↑ │ MMU页表映射(页级映射、权限控制) │ 虚拟内存(Virtual Memory) ↑ │ 内核为不同进程划分虚拟地址空间(空间隔离) │ 虚拟地址空间布局(Address Space Layout) ↑ │ 每个进程看到的内存分布(代码段/堆/栈) │ 用户进程的虚拟内存布局(User Process Memory Layout) 

也就是说:

  • 物理内存 是硬件层面上真实存在的存储单元;
  • 虚拟内存 是 CPU + OS 提供的逻辑抽象,让每个进程都“以为自己独占整块内存”;
  • 虚拟地址空间布局 是虚拟内存被 OS 组织的结构;
  • 用户进程的虚拟内存布局 是其中“属于用户态部分”的子集。

八、逐层详解与对应关系

1. 物理内存(Physical Memory)
  • 硬件真实存在:即 DRAM 芯片中的存储单元。
  • 每个物理页帧有一个编号(PFN,Page Frame Number)。
  • OS 通过 页表 把“虚拟页”映射到“物理页帧”。

例:

物理地址: [0x00000000 - 0x001FFFFF] -> 2MB [0x00200000 - 0x003FFFFF] -> 2MB ... 

2. 虚拟内存(Virtual Memory)
  • MMU(内存管理单元) + 页表(page table) 实现。
  • 每个进程拥有独立的虚拟地址空间(通常64位系统为128TB)。
  • 虚拟页(Virtual Page)通过页表映射到物理页(Physical Page)。
🧩 关键特征:隔离 + 保护每个进程互不干扰;访问非法页 → 触发页错误(segfault)。

3. 虚拟地址空间布局(Address Space Layout)

虚拟内存不是乱放的,Linux 内核会为其分区:

  • 用户空间(User Space)
  • 内核空间(Kernel Space)

典型划分(x86_64):

用户空间: 0x0000_0000_0000_0000 ~ 0x0000_7fff_ffff_ffff 内核空间: 0xffff_8000_0000_0000 ~ 0xffff_ffff_ffff_ffff 

这称为虚拟地址空间布局
它描述了“整个虚拟内存范围”的全局分布。


4. 用户进程的虚拟内存布局(User Process Memory Layout)

在用户空间内部,Linux 又进一步划分为:

区域说明典型增长方向
text程序代码段固定
data已初始化的全局变量固定
bss未初始化的全局变量固定
heap动态分配区(malloc/brk)向上增长 ↑
mmap动态映射区(共享库/匿名映射)向下增长 ↓
stack线程栈向下增长 ↓

简图如下:

高地址 +------------------+ | Stack | 向下增长 +------------------+ | Mapped files | +------------------+ | Heap | 向上增长 +------------------+ | BSS, Data, Text | 低地址 

九、 三者之间的关系总结

层次描述映射/包含关系
物理内存真正的RAM硬件被“页表”映射到虚拟内存
虚拟内存OS提供的逻辑内存抽象由物理页 + 交换区(swap)组成
虚拟地址空间布局整个虚拟内存空间的结构(用户 + 内核)定义虚拟内存的全局分区
用户进程虚拟内存布局用户空间部分的细分结构(代码、堆、栈等)是虚拟地址空间的一部分

十、 举个例子:进程访问内存时的路径

当一个用户进程执行 x = *p; 时:

1️⃣ p 是一个 虚拟地址(属于用户虚拟空间)。
2️⃣ MMU 查页表 → 得到对应的 物理页帧号(PFN)
3️⃣ 访问该物理页中的内容。
4️⃣ 如果该页还没在内存中(比如在磁盘swap),会触发缺页中断,由内核加载后再返回。

即:

虚拟地址(用户视角) ↓ 页表映射 物理地址(硬件视角) ↓ 存取DRAM 实际数据 
👉 虚拟内存(Virtual Memory) 是操作系统为了解决“内存有限、程序多样、安全隔离、方便编程”等问题而引入的抽象层
它让每个进程都“以为”自己拥有独立且连续的完整内存空间。

十一、为什么需要虚拟内存(动机)

假设我们没有虚拟内存,程序直接访问物理内存地址

  • 程序A加载到物理地址 0x00000000
  • 程序B加载到物理地址 0x00100000

这样会导致一堆问题

问题说明
① 内存冲突问题不同程序可能访问同一物理地址,互相覆盖数据。
② 内存分配困难程序加载地址不连续,碎片化严重。
③ 安全隔离困难程序可以随意访问别的程序或内核空间。
④ 多任务调度麻烦程序切换时需要保存和恢复物理地址映射。
⑤ 扩展性差程序必须适应“物理内存大小限制”。

于是,操作系统与硬件设计者提出了一个“虚拟化”的方案👇

✅ “让每个进程看到的地址空间都一样,但实际背后映射到不同的物理内存。”

十二、虚拟内存的核心思想

1️⃣ 地址虚拟化(Address Virtualization)

每个进程看到的内存空间是“虚拟地址空间”,
通过 MMU(Memory Management Unit) + 页表(Page Table)
把虚拟地址 → 物理地址 映射。

🧩 每个进程都以为:

实际上不同进程的 0x00000000 会被映射到不同的物理页。

2️⃣ 页式管理(Paging)

把内存分成固定大小的页(通常4KB):

  • 虚拟内存页(Virtual Page)
  • 物理页帧(Physical Frame)

操作系统通过页表控制两者映射关系。
这样:

  • 虚拟内存可以不连续
  • 物理内存可以动态调度
  • 程序可以只加载部分页

3️⃣ 结合磁盘(Swap / Page Cache)

虚拟内存不仅映射到物理RAM,也可以映射到磁盘文件交换区(swap)
当物理内存不足时,不常用的页可以被换出(swap out),
再次访问时再换入(page fault + swap in)。

🧠 这让程序“看起来”拥有的内存空间远大于实际物理内存!

十三、虚拟内存带来的主要优势

目的描述举例
内存保护(隔离)每个进程拥有独立的地址空间,互不干扰程序A无法访问程序B的内存
简化编程模型程序认为自己有连续内存,不需关心物理碎片数组/指针可直接用线性地址
支持多任务并发操作系统可自由调度不同进程,共享物理内存任务切换只需切页表
内存扩展(虚拟化)可以使用磁盘模拟更多内存即使RAM只有8GB,也能运行10GB程序
共享内存机制允许部分页映射到相同物理页多进程共享libc.so库
高效I/O映射设备寄存器、文件可映射到地址空间mmap()机制

十四、举个直观例子

假设你的电脑只有 4GB RAM
但你同时运行:

  • Chrome:需要 2GB
  • VSCode:需要 1GB
  • Python:需要 2GB

物理内存总需求 5GB > 实际4GB
👉 通过虚拟内存:

进程虚拟地址空间实际物理页交换区(磁盘)
Chrome8GB部分页驻留RAM冷页换出
VSCode8GB部分页驻留RAM冷页换出
Python8GB部分页驻留RAM冷页换出

每个进程都认为自己“拥有”8GB地址空间,
但 OS 只把当前活跃的部分页保留在 RAM 中,
其他暂时不用的页放到磁盘中。


十五、简化结构图(逻辑示意)

用户视角 (虚拟地址空间) +------------------------------+ | Stack | Heap | Data | Text | +------------------------------+ ↓ 页表映射 +------------------------------+ | 部分在物理RAM | | 部分在磁盘Swap | +------------------------------+ 物理视角 (真实内存 + 磁盘) 

十六、总结一句话

层次没有虚拟内存时有了虚拟内存后
内存访问程序直接操作物理地址程序操作虚拟地址,系统自动映射
程序隔离相互影响、容易崩溃地址空间隔离、安全
内存利用碎片化严重灵活调度、支持换页
程序设计复杂、需考虑实际地址简单、线性逻辑

Read more

如何将代码轻松上传到 Gitee?Git 使用全攻略!

如何将代码轻松上传到 Gitee?Git 使用全攻略!

在开发过程中,代码托管平台是每个开发者的必备工具。无论你是刚接触版本控制的新手,还是已经拥有多项目管理经验的程序员,掌握如何将代码上传到 Gitee 或 GitHub 都是必不可少的技能。 今天,我将带你一步步了解 如何将项目上传到 Gitee,并且在过程中顺便深入解析 Git、Gitee 和 GitHub 的关系,让你在使用这些工具时不再迷茫。 一、准备工作:Git 基础知识 首先,我们需要知道 Git 是什么,它是如何与 Gitee 和 GitHub 配合使用的。 1.1 什么是 Git? Git 是一款开源的分布式版本控制工具,旨在帮助程序员管理代码历史、团队协作以及代码合并。无论你是一个人开发项目,还是和团队一起协作,Git 都能帮助你: * 跟踪代码的更改 * 回退到任何历史版本 * 合并团队成员的修改 1.2

By Ne0inhk
构建代码库知识图谱解决方案-GitNexus 项目技术分析总结

构建代码库知识图谱解决方案-GitNexus 项目技术分析总结

GitNexus 项目技术分析总结 Building git for agent context. 为 AI 智能体构建代码库知识图谱的完整解决方案 一、项目概述 1.1 核心问题 GitNexus 解决的是 AI 代码助手(如 Cursor、Claude Code、Windsurf)缺乏对代码库深层结构理解 的问题。github地址:https://github.com/abhigyanpatwari/GitNexus 传统痛点: * AI 编辑代码时,无法感知依赖关系 * 修改一个函数,不知道 47 个函数依赖其返回值类型 * 导致破坏性变更被直接提交 GitNexus 的解决方案: 通过构建知识图谱(Knowledge Graph),将代码库的依赖、调用链、功能集群和执行流程全部索引,并通过

By Ne0inhk
2026 Git 安装流程和基础使用步骤(保姆级教程)

2026 Git 安装流程和基础使用步骤(保姆级教程)

文章目录 * 前言 * 一、 Git 下载与保姆级安装步骤 * 二、 环境配置 * 配置 Notepad++ 为默认编辑器 * 三、 从零开始:Git 基础工作流 * 四、 新手必看:高频“翻车”坑点与解决方案 前言 Git 工具大家应该挺熟悉的,Git 是管理代码的工具,无论是在搭建前后端分离的复杂架构,还是在调试庞大的深度学习模型,一个清晰、规范的版本控制系统能帮你避开无数次“代码重构”带来的崩溃。Git 工具在大学期间实训时和工作中都会用到,那么今天在新电脑上手把手安装 Git 工具。 一、 Git 下载与保姆级安装步骤 前往 Git 官方网站(https://git-scm.com/),如下图点击 下载最新的 64-bit Git for Windows

By Ne0inhk
2025最新在GitHub上搭建个人图床,保姆级图文教程,实现图片高效管理

2025最新在GitHub上搭建个人图床,保姆级图文教程,实现图片高效管理

文章目录🌍一. 图床❄️1.什么是图床❄️2.图床能解决什么问题?🌍二. 在github上面创建图床🌍三. PicGo❄️1. PicGo介绍❄️ 2. 下载与安装❄️3. 配置图床❄️3.错误解决问题1问题2问题3问题4🌍 四. Typora❄️一. 破解版安装❄️二. 设置Typora实现自动上传 🙋‍♂️ 作者:@whisperrr.🙋‍♂️ 👀 其他专栏:JavaWeb👀 💥 标题:2025最新在GitHub上搭建个人图床,保姆级图文教程,实现图片高效管理💥 ❣️ 寄语:比较是偷走幸福的小偷❣️ 在数字化时代,图片已成为我们日常沟通和表达的重要方式。无论是社交媒体、博客还是论坛,图片都是不可或缺的元素。然而,随着图片数量的不断增加,如何高效地存储和分享图片成为了一个难题。这时候,图床应运而生,成为解决这一问题的利器。 🌍一. 图床 ❄️1.什么是图床

By Ne0inhk