Vince Jiang

CSCI3150 / 课程伴读 · 本站更新

CSCI3150 L09 Address Space

课程:CSCI3150 Introduction to Operating Systems · 2022未核 本讲:L09 Address Space,第 1 部分 / 共 2 部分 · 原件 L09-地址空间与地址转换-2022未核.pptx(本地课件) · PDF页码副本(本地课件) p.1–14 定位:从多程序驻留的保护问题理解地址空间,并能把代码、静态数据、堆、栈与程序打印的虚拟地址对应起来。 前后:下一份 Part II 承接:#L01-05 进程私有虚拟地址空间

整讲导航:Part I 地址空间,p.1–14;Part II 地址转换,p.15–45。

p.1标题页。p.2课程图转入内存虚拟化;p.3回顾CPU、内存、磁盘共享与系统调用的关系。p.4 Part I分节页。

每个进程为什么看到自己的内存

虚拟内存的三个目标(p.5–6)【延伸 L01 p.12–16】

p.5 What is memory virtualization?

OS virtualizes its physical memory.

OS provides an illusion memory space per each process.

It seems to be seen like each process uses the whole memory .

p.6 Ease of use in programming

Memory efficiency in terms of time and space

The guarantee of isolation for processes as well as OS

Protection from errant accesses of other processes

p.5的“illusion”指每个进程使用自己的地址视图,不必知道真实物理布局。它不是保证每个进程随时独占全部实际RAM。p.6列易用性、时空效率和隔离:程序易于管理自己的对象;实现不能为每次访存付出过高代价;出错进程不应任意破坏别人或内核。

隔离是需要检查与权限支持的目标,不会仅因把地址叫“virtual”自动出现。下一Part从最简单的加基址与界限检查解释这种支持。

从单程序到多程序驻留(p.7–8)

p.8 Load multiple processes in memory.

Execute one for a short while.

Switch processes between them in memory.

Increase utilization and efficiency.

Cause an important protection issue.

Errant memory accesses from other processes

图(p.7–8):同一物理内存的两种安排 元素:p.7低0–64KB为OS,余下只有当前程序;p.8同样保留OS,再分布进程C、B、A与空闲区,其中A在320–384KB。 看什么:多个进程同时驻留后,切换可直接选择另一个已驻留进程,但错误地址也可能落入他人的区域。

p.7只有一个用户程序时,等待I/O容易浪费CPU。p.8让多个程序留在内存以配合分时;“驻留多个”不等于单核“瞬间执行多个”。算一遍:图中A占384−320=64KB,B占256−192=64KB,C占192−128=64KB。三个用户区域合计192KB,而空闲区仍散布其间,不能把空闲总量当成一个连续区域。

代码、静态数据、堆和栈(p.9–11)【新】

p.9 OS creates an abstraction of physical memory.

The address space contains all about a running process.

That is consist of program code, data, heap, and stack

p.10 Code

Where instructions live

Data

Global or static local variables

Heap

Dynamically allocate memory.

malloc in C language

new in object-oriented language

Stack

Store return addresses or values.

Contain local variables arguments to routines.

p.9在16KB虚拟空间中把代码/数据放低端,堆从较低位置增长,栈在高端;中间留空以便增长。p.10逐一解释:code存指令;data存全局或静态局部变量;heap承载malloc等动态分配;stack存返回地址、调用参数和局部执行状态。变量在函数里声明不保证都属于栈,static局部变量就是本页特别指出的区别。

p.11的Linux图进一步列Text、Data、BSS、Heap、MMAP、Stack,左侧task_struct关联mm_struct,后者描述各范围,页表再把虚拟范围连接到物理内存。补充:BSS通常表示未显式初始化的静态存储区域;图画的是概念布局,现代程序的实际位置要现场查映射,不能背一个固定绝对地址。

图(p.11):进程内存描述与映射 元素:task_struct→mm_struct,多个虚拟区域经page table→physical memory;heap与stack有相反增长箭头。 看什么:虚拟区域的连续排列不证明它们在物理内存中也连续。

p.11 的完整区域与标记。 从低地址向高地址,原图列出 Text、Data、BSS、Heap、MMAP、Stack。Text 的界限标为 start_code/end_code,Data 标为 start_data/end_data,堆的起点和当前边界为 start_brk/brk;mmap_base 标记映射区域基准,栈图标出 stack_start/stack_end。图中堆箭头向高地址、MMAP 和栈箭头向低地址。右侧简图把 data 标为 initialized data、bss 标为 uninitialized data,中间留白供堆与栈增长。箭头说明这一概念布局的增长方向,不能推出两者最终可以安全碰到一起;地址空间还有映射、保护和容量约束。

补充:按生命周期给变量分类,而非只看声明位置。 在一个函数中,int x=1 是自动存储期局部对象;static int y=1 的名字也只在该函数范围可见,但对象跨调用持续存在;int *p=malloc(16) 同时涉及局部指针 p 和另一个动态分配对象。p 的保存位置与它所指对象的位置不是同一个问题。

函数返回后,普通局部 x 的生命周期结束,不能把 &x 交给调用者当长久有效对象;动态对象则不会因为保存它的局部指针离开作用域而自动 free。若唯一指针丢失,会泄漏;若明确把所有权交给调用者,则由调用者在用完后释放。代码、静态数据、堆、栈的图帮助理解常见实现,但 C 对象存储期才是判断“现在还能不能用”的语义依据,编译器优化也可能把局部值保留在寄存器中。

自测:malloc(1) 返回地址比映射起点大16字节,能否断定前16字节全是本次对象内容?

不能。返回对象保证的是请求的可用范围;映射包含分配器管理的区域,可能有元数据、对齐或其他对象。地址差只说明位置关系,不能从中反推出完整分配器布局,也不能授权访问 p 前面的16字节。

打印地址能观察到什么(p.12–14)

p.12 Every address in a running program is virtual.

OS translates the virtual address to physical address

课件程序与接口(p.12,原页片段)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]){

    printf("location of code  : %p\n", (void *) main);
    printf("location of heap  : %p\n", (void *) malloc(1));
    int x = 3;
    printf("location of stack : %p\n", (void *) &x);

    return x;
}

p.14 cat /proc/<pid_number>/maps pmap -x <pid_number>

p.12分别打印main函数、malloc(1)返回指针和局部变量x的地址;三者对应代码、堆、栈。p.13示例为0x40057d、0xcf2010、0x7fff9ca45fcc,它们全是该进程所用虚拟地址,不能据此直接定位RAM芯片位置。

算一遍:图中的代码范围0x400000–0x401000,main偏移0x57d=1405字节;堆起点0xcf2000,返回地址0xcf2010距离起点0x10=16字节。这个差值告诉你返回对象在映射中的位置,不能证明分配器只消耗了1字节物理内存。

p.14演示cat /proc/<pid>/maps和pmap -x <pid>,用于查看映射范围、权限及映射对象。图中的地址是旧示例运行结果;代码地址高低、堆位置可能因平台与运行配置变化。此处不执行命令,重点是知道“进程映射”和“物理地址”是不同观察层次。

考试角度:(C 级 通识)常见考法是把某变量或打印地址归入代码、静态数据、堆或栈,并解释两个进程地址相同为何不代表数据共享。

p.14 截图的映射记录(按原图转录)。 这是 PID 10534 的历史示例;它与 p.13 不是同一次运行,地址不能拼接使用。下表把重复路径缩写为 test、libc、ld:分别是 /home/csci3150/process-memory-test/test、/lib/i386-linux-gnu/libc-2.27.so、/lib/i386-linux-gnu/ld-2.27.so。空名称用 — 表示。

虚拟地址区间 权限 文件偏移 设备 inode 映射对象
004cd000–004ce000 r-xp 00000000 08:01 136307 test
004ce000–004cf000 r--p 00000000 08:01 136307 test
004cf000–004d0000 rw-p 00001000 08:01 136307 test
b7d93000–b7f68000 r-xp 00000000 08:01 526179 libc
b7f68000–b7f69000 ---p 001d5000 08:01 526179 libc
b7f69000–b7f6b000 r--p 001d5000 08:01 526179 libc
b7f6b000–b7f6c000 rw-p 001d7000 08:01 526179 libc
b7f6c000–b7f6f000 rw-p 00000000 00:00 0 —
b7f83000–b7f85000 rw-p 00000000 00:00 0 —
b7f85000–b7f88000 r--p 00000000 00:00 0 [vvar]
b7f88000–b7f8a000 r-xp 00000000 00:00 0 [vdso]
b7f8a000–b7faf000 r-xp 00000000 08:01 526151 ld
b7fb0000–b7fb1000 r--p 00025000 08:01 526151 ld
b7fb1000–b7fb2000 rw-p 00026000 08:01 526151 ld
bf829000–bf84a000 rw-p 00000000 00:00 0 [stack]

怎样读一行(补充解释)。 区间右端不包含在内。第一行长度是 0x004ce000−0x004cd000=0x1000=4096 字节。r/w/x 分别表示读、写、执行,短横表示该权限没有,p 表示私有映射;这些权限属于虚拟映射,不能解释成“磁盘文件一定只有这个权限”。文件偏移指出该映射从后备文件何处开始;设备和 inode 标识后备文件,匿名区域不靠这两列指向普通文件。[stack] 是栈,[vvar] 与 [vdso] 是系统提供的特殊映射;本讲不要求展开其内核实现。

同一截图右边的 pmap -x 10534 用 Address、Kbytes、RSS、Dirty、Mode、Mapping 六列观察同一类区域。原图每个实际映射行后还有一行全零计数;下面保留这些行,不把它们加成另一份内存。

Address   Kbytes RSS Dirty Mode  Mapping
004cd000       4   4     0 r-x-- test
004cd000       0   0     0 r-x-- test
004ce000       4   4     4 r---- test
004ce000       0   0     0 r---- test
004cf000       4   4     4 rw--- test
004cf000       0   0     0 rw--- test
b7d93000    1876 688     0 r-x-- libc-2.27.so
b7d93000       0   0     0 r-x-- libc-2.27.so
b7f68000       4   0     0 ----- libc-2.27.so
b7f68000       0   0     0 ----- libc-2.27.so
b7f69000       8   8     8 r---- libc-2.27.so
b7f69000       0   0     0 r---- libc-2.27.so
b7f6b000       4   4     4 rw--- libc-2.27.so
b7f6b000       0   0     0 rw--- libc-2.27.so
b7f6c000      12   8     8 rw--- [ anon ]
b7f6c000       0   0     0 rw--- [ anon ]
b7f83000       8   8     8 rw--- [ anon ]
b7f83000       0   0     0 rw--- [ anon ]
b7f85000      12   0     0 r---- [ anon ]
b7f85000       0   0     0 r---- [ anon ]
b7f88000       8   4     0 r-x-- [ anon ]
b7f88000       0   0     0 r-x-- [ anon ]
b7f8a000     152 152     0 r-x-- ld-2.27.so
b7f8a000       0   0     0 r-x-- ld-2.27.so
b7fb0000       4   4     4 r---- ld-2.27.so
b7fb0000       0   0     0 r---- ld-2.27.so
b7fb1000       4   4     4 rw--- ld-2.27.so
b7fb1000       0   0     0 rw--- ld-2.27.so
bf829000     132  12    12 rw--- [ stack ]
bf829000       0   0     0 rw--- [ stack ]
total kB    2236 904    56

读数含义(补充)。 Kbytes 是映射大小,RSS 是当时驻留部分,Dirty 是相应脏页统计;原图总计分别为 2236、904、56 KiB,三列回答不同问题,不能把 2236 当成全部已占用物理页。以 libc 第一段为例,0xb7f68000−0xb7d93000=0x1d5000,除以 1024 得 1876,而 RSS 仅 688。截图中的权限和地址是例子的观察结果,不是所有 Linux 进程都应输出的固定模板。

补充:虚拟范围、驻留量与实际使用量不是同一个尺寸。 映射表的一行先描述进程能以哪些地址和权限访问某段范围;它不直接证明范围中的每个字节都已经对应一份独占的物理 RAM。文件映射、共享页和暂未驻留页都使“把虚拟区间长度相加”与“本进程独占了多少 RAM”不同。反过来,只看 malloc 请求的字节数,也看不到代码、栈、映射和管理结构等其他占用。

读本页 maps/pmap 输出时,先逐列写单位:起止地址相减得到字节范围,权限说明读写执行许可,Resident 表示当前驻留统计,Dirty 表示修改状态。两个进程映射了同一共享对象,分别统计时可能各自显示它;把两份进程统计简单相加未必等于系统实际占用翻倍。这里不需要猜一个真实地址,只需知道每一列回答的问题,才能避免拿地址空间图当 RAM 实物清单。

本讲核心考点

  • 虚拟化追求易用、效率与隔离(p.5–6,C 级通识考法)。
  • 虚拟布局不等于物理布局(p.7–11,C 级通识考法)。
  • 指针打印的是虚拟地址,maps观察的是映射(p.12–14,C 级通识考法)。

附录

本份没有需要移至附录的长推导;计算过程已在对应页正文写全。

来源与证据

  • 原件:L09-地址空间与地址转换-2022未核.pptx(本地课件);PDF副本(本地课件) p.1–14。本文页码均为 PDF 页号。

  • 考试证据:读了 课程大纲-2026T1.pdf、教学计划-2026T1.pdf、T08-期中参考-2025T2-题目-解答.pdf、T07-多级反馈队列-2025T2.pdf(p.13–15内嵌历史试题);未识别用途的 PDF:无

  • 2026-10-13 内容补全:保留原页顺序与版本,补入对应页的程序、接口、字段、条件和演算;原程序片段保留课件行号、拼写与省略处,不能据此视为经过编译的完整软件。本文已有运行记录属于其标注日期,本次未重新运行课程容器或提交作业。