Linux---进程(八)程序地址空间(虚拟地址空间)

1、进程虚拟空间的布局

如下图可以看清楚代码段在低地址;只读数据段、数据段、BSS段依次向上;堆区从低地址向高地址增长;栈区从高向低地址增长;命令行参数和环境变量位于栈的最顶端。

2、虚拟地址引入

虚拟地址是进程看到的"逻辑地址",操作系统通过页表和写时复制,让相同的虚拟地址对应不同的物理内存,从而实现了进程间的地址隔离和高效内存管理。

如下图:

从输出可以清晰看到:

  • 子进程: child[30501]: 100 : 0x601058
  • 父进程: parent[30500]: 0 : 0x601058

这里的核心现象是:

  • 变量值不同:子进程里 g_val 是 100 ,父进程里 g_val 还是 0 。

  • 变量地址相同:两者的变量地址都是 0x601058 。

通俗解释

  • 地址相同:这个地址是虚拟地址,每个进程都有自己独立的虚拟地址空间,所以父子进程里同一个变量的虚拟地址可以完全一样。

  • 值不同:子进程修改 g_val 时,操作系统触发了写时复制(COW),给子进程单独分配了一块物理内存,把修改后的值存在了新的物理页上。所以,虽然虚拟地址相同,但它们实际对应的物理内存已经是两块不同的区域,因此值互不影响。

虚拟地址总结

虚拟地址是进程自己看到的"门牌",操作系统通过页表把相同的"门牌"映射到了不同的"房间"(物理内存),所以值不一样。

  1. 刚 fork() 完
  • 父子进程共用同一块物理内存

  • 虚拟地址一样,物理地址也一样

  1. 子进程一修改数据
  • 操作系统发现:有人要改共享内存

-立刻给子进程新开辟一块物理内存
- 把原来的数据复制过去
- 只修改子进程的页表,让它的虚拟地址指向这块新物理内存

  1. 结果
  • 子进程改的是新物理内存

  • 父进程还是用老物理内存

  • 所以:子进程怎么改,都完全不影响父进程

最简总结:

虚拟地址没变 → 页表变了 → 物理内存换了

这就是:写时复制(COW)

虚拟地址空间概念

虚拟地址空间是OS给进程画的一张饼

OS对虚拟地址空间的管理

系统中有很多的进程,每个进程有自己的虚拟地址空间,所以OS要管理这些虚拟地址空间,

操作系统给每个进程"伪造"了一整片连续的地址空间,

这就叫虚拟地址空间。

每个进程的虚拟地址空间,

都由一个叫 struct mm_struct 的结构体来管理。

操作系统通过管理所有进程的 mm_struct ,

实现对所有虚拟地址空间的统一管理。

操作系统负责管理所有进程的虚拟地址空间。

  • 每个用户进程:

→ 有一个 struct mm_struct

  • 操作系统:

→ 通过管理一堆 mm_struct 来管理所有虚拟地址空间

如何理解虚拟地址空间中的区域划分?

我用最简单、最考试、最能记住的方式,只讲核心,你一下就懂:

虚拟地址空间的区域划分 ------ 一句话理解

就是把进程那块"假的虚拟地址",按用途分成好几块,每块干不同的事,互不干扰。

为什么要划分?

  • 代码不能随便改

  • 数据可以读写

  • 函数调用要用栈

  • malloc 要用堆

如果不分区,全部混在一起,程序一跑就崩溃。

所以操作系统把虚拟地址空间分成不同区域,这就叫:区域划分

分成哪几个区?(只记最核心 4 个)

  1. 代码区

放程序代码,只读,不能改。

  1. 数据区

放全局变量、静态变量。

  1. 堆区(heap)

malloc 动态申请内存用,从下往上长。

  1. 栈区(stack)

局部变量、函数调用用,从上往下长。

总结:

虚拟地址空间是假的地址范围,

操作系统为了安全、好管理,

把它按功能分成不同区域,

这就叫 虚拟地址空间的区域划分。

1、什么是页表?

页表是操作系统维护的地址映射表,负责将进程的虚拟地址翻译成物理内存的真实地址,每个进程有独立的页表。

2. 查表工作谁来做?

主要由 CPU 内的 MMU(内存管理单元) 硬件完成。

发生页缺失时,由操作系统内核介入处理。

3. 为什么要有虚拟地址空间?

隔离保护:进程间互不干扰,提升系统稳定性。

简化编程:程序员无需关心物理内存细节。

高效利用:通过分页、共享、交换等技术,突破物理内存限制。

地址规整:提供连续的虚拟地址块,方便内存管理。

或:

  1. 控制进程的行为(拦截进程的非法行为),保护物理内存。

  2. 有了虚拟地址空间和页表,原则上:将进程的内存空间布局,无序变有序。

  3. 让进程管理和内存管理,解耦合

懒加载

在 Linux 进程创建和内存管理的语境下,懒加载(Lazy Loading / 延迟加载) 指的是:

进程创建时,操作系统不立即把代码和数据全部加载到物理内存,而是先创建好内核数据结构(如 task_struct 、 mm_struct 、页表等),建立好虚拟地址空间的映射关系。

当进程真正执行到某段代码、访问某个数据时,发现对应的页不在物理内存里,触发页错误(Page Fault),操作系统才会把那一页的内容从磁盘加载到内存,并更新页表。

相关推荐
幸福指北7 小时前
我用 Tauri + Vue 3 + Rust 开发了这款跨平台网络连接查看工具PortView,性能炸裂!
运维·网络·监控
V__KING__8 小时前
systemd-remount-fs,fstab之间的渊源
linux·服务器·网络
酿情师8 小时前
Windows Subsystem for Linux (WSL, Ubuntu)安装教程(详细)
linux·windows·ubuntu
Titan20249 小时前
Linux环境变量个人笔记
linux·服务器·c++
zx_zx_1239 小时前
传输层协议tcp (2)
服务器·网络·tcp/ip
青柠代码录9 小时前
【Linux】路径区分:testdir、testdir/、testdir/*
linux·运维·服务器
7yewh9 小时前
jetson_yolo_deployment 02_linux_dev_skills
linux·python·嵌入式硬件·yolo·嵌入式
supersolon9 小时前
Windows下WSL(Ubuntu24.04)安装Nodejs
linux·ubuntu·node.js
进击切图仔10 小时前
跨系统时间戳同步问题解决总结
linux
Benszen10 小时前
Docker容器化解决方案全解析
运维·docker·容器