C++ / a working model

120 / 163   ·   C11   ·   约 8 分钟

分段

先记住这句话

分段用多组独立的基址与界限寄存器把代码、堆、栈分别放到物理内存的不同位置,从而避免稀疏地址空间中的空洞浪费物理页。

本篇内容
  1. 单一基址界限对的浪费
  2. 每段独立的基址与界限
  3. 用高位选择段并检查偏移
  4. 段扩展与外部碎片
  5. 运行示例
  6. 动手练习

官方章节 PDF

单一基址界限对的浪费

把整个虚拟地址空间连续搬进物理内存时,堆与栈之间的空洞仍然占用真实RAM。32位空间里程序可能只用几兆,空洞却可达数GB,既浪费又难以运行大于物理内存的映像。

每段独立的基址与界限

硬件为每个逻辑段(代码、堆、栈)配备一对寄存器。操作系统因此可以把各段放到物理内存任意空闲区域,只为真正使用的字节分配空间,稀疏地址空间因而变得可行。

用高位选择段并检查偏移

虚拟地址的高几位直接索引段寄存器,剩余位作为段内偏移。硬件先比较偏移与界限,越界立刻陷入;合法时再把基址加上偏移得到物理地址。

段扩展与外部碎片

虽然空洞不再占用内存,但要把某个段变大仍需找到足够大的连续物理空洞。长期运行后物理内存会出现许多不规则碎片,这是分段留下的主要管理难题。

常见误区

  • 把整个虚拟地址直接加到基址上而忘记先抽出段内偏移
  • 用高位选段会把每个段的最大长度锁死在地址空间的固定切片内

运行一个例子

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

#include <stdio.h>
#include <stdint.h>

int main(void) {
    const uint32_t base[3] = {32u * 1024, 34u * 1024, 28u * 1024};
    const uint32_t bounds[3] = {2u * 1024, 3u * 1024, 2u * 1024};
    const char *names[3] = {"code", "heap", "stack"};
    const uint32_t vas[3] = {100, 4200, 7168};
    for (int i = 0; i < 3; i++) {
        uint32_t va = vas[i];
        uint32_t seg = (va >> 12) & 3u;
        uint32_t offset = va & 0xFFFu;
        printf("VA %u (0x%x): ", va, va);
        if (seg > 2u) {
            printf("invalid segment\n");
            continue;
        }
        if (offset >= bounds[seg]) {
            printf("segmentation fault (offset %u >= %u in %s)\n",
                   offset, bounds[seg], names[seg]);
        } else {
            uint32_t pa = base[seg] + offset;
            printf("segment %s, offset %u -> PA %u\n",
                   names[seg], offset, pa);
        }
    }
    return 0;
}

在本地编译

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-16-segmentation.c -o example && ./example

预期结果

VA 100 (0x64): segment code, offset 100 -> PA 32868
VA 4200 (0x1068): segment heap, offset 104 -> PA 34920
VA 7168 (0x1c00): segmentation fault (offset 3072 >= 3072 in heap)

CHECK YOUR UNDERSTANDING

合上答案,试着解释。

14位虚拟地址0x0500,高2位选择段。代码段基址32768、大小2048。请给出物理地址或说明是否产生段错误。

查看参考答案

高2位为00,选中代码段。偏移0x500=1280小于2048,合法。物理地址=32768+1280=34048。

继续查证

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

回到目录