C++ / a working model

117 / 163   ·   C11   ·   约 8 分钟

抽象:地址空间

先记住这句话

本章介绍操作系统如何将物理内存抽象为每个进程私有的地址空间,使多个程序能同时驻留内存并安全运行,同时保持对程序员透明。

本篇内容
  1. 早期机器上几乎没有内存幻觉
  2. 多道程序与分时迫使进程同时留在内存
  3. 进程眼中的私有内存:代码、堆与栈
  4. 虚拟化内存的核心任务与目标
  5. 运行示例
  6. 动手练习

官方章节 PDF

早期机器上几乎没有内存幻觉

最初的计算机把物理内存原样交给程序。操作系统占据最低的一段地址,剩下的全部给当时唯一正在运行的作业。程序员直接面对硬件布局,一次只能执行一个程序,隔离和保护几乎不存在。

多道程序与分时迫使进程同时留在内存

机器极其昂贵,人们开始让多个作业同时准备运行。当一个进程等待I/O时操作系统切换到另一个,从而提高CPU利用率。随后出现的分时系统要求交互响应,把整个内存映像换到磁盘再换回来太慢,因此多个进程必须同时占用物理内存,保护问题立刻变得尖锐。

进程眼中的私有内存:代码、堆与栈

地址空间是进程看到的全部内存。低地址存放不可变的程序指令,紧接着是向高地址增长的堆(供动态分配使用),最高处是向低地址增长的栈(保存局部变量和返回地址)。这种两端放置的约定让两个可增长区域尽量推迟相遇。实际物理位置由操作系统决定,进程自己并不知道。

虚拟化内存的核心任务与目标

操作系统必须在单一物理内存上为每个进程制造“从零开始的巨大私有空间”的假象,同时保证互不干扰。实现手段是硬件地址转换加上操作系统维护的映射表。目标包括对程序完全透明、转换足够快、以及严格的隔离保护。

常见误区

  • 误以为虚拟地址就是物理地址
  • 把堆和栈放在地址空间同一端导致立刻溢出

运行一个例子

最低标准 C11 · 完整程序 · 下载 .c

#include <stdio.h>

int main(void) {
    puts("Address space simulation (virtual view):");
    puts("0x0000: program code (text)");
    puts("0x1000: heap start (grows up)");
    puts("0xF000: stack start (grows down)");
    puts("The OS maps these virtual addresses to physical RAM.");
    return 0;
}

在本地编译

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-13-address-spaces.c -o example && ./example

预期结果

Address space simulation (virtual view):
0x0000: program code (text)
0x1000: heap start (grows up)
0xF000: stack start (grows down)
The OS maps these virtual addresses to physical RAM.

CHECK YOUR UNDERSTANDING

合上答案,试着解释。

为什么典型地址空间把堆和栈放在两端而不是同一侧?

查看参考答案

这样两者能相向独立增长,只有当进程真正耗尽几乎全部空间时才会相遇,从而最大化可用动态内存。

继续查证

标准草案与官方章节会更新;版本标记只说明示例最低要求。

回到目录