Vince Jiang

CSCI3150 / 课程伴读 · 本站更新

CSCI3150 L10 分段

课程:CSCI3150 Introduction to Operating Systems · 2022未核 本讲:L10 分段,第 1 部分 / 共 2 部分 · 原件 L10-分段与分页-2022未核.pptx(本地课件) · PDF页码副本(本地课件) p.1–17 定位:把整片地址空间的基址与界限,改为各逻辑段自己的基址与界限。 前后:接 L09 地址转换;后接 分页。

逐页伴读

p.1 是讲题;p.2–3 把本讲放回内存虚拟化:进程产生虚拟地址,硬件检查并转换,OS 维护映射。p.4 是 Part I 标题。

p.5–7:为什么不能把空白也搬进物理内存

p.5 Big chunk of “free” space

“free” space takes up physical memory.

Hard to run when an address space does not fit into physical memory

p.6 Segment is just a contiguous portion of the address space of a particular length.

Logically-different segment: code, stack, heap

Each segment can be placed in different part of physical memory.

Base and bounds exist per each segment.

前讲用一对寄存器搬整个地址空间。图 p.5 中代码、堆、栈之间的大块空白也占据那块连续物理区域,即使程序没用它。分段把逻辑上不同的区域分别安放,空白不必得到物理内存。

图 p.7 的元素是三个段与物理地址轴;要看的是各段连续,但段与段之间不必连续。Code 基址 32 KiB、长度 2 KiB,Heap 基址 34 KiB、长度 2 KiB,Stack 的高端基址 28 KiB、长度 2 KiB。因此代码占 [32,34) KiB,堆占 [34,36) KiB,向下增长的栈占 [26,28) KiB。不要把栈误放在 [28,30)。

p.8–10:先求段内偏移,再加物理基址

p.8 The offset of virtual address 100 is 100.

The code segment starts at virtual address 0 in address space.

p.9 The offset of virtual address 4200 is 104.

The heap segment starts at virtual address 4096 in address space.

p.10 If an illegal address such as 7KB which is beyond the end of heap is referenced, the OS occurs segmentation fault.

The hardware detects that the address is out of bounds.

原例给代码中的虚拟地址 100、堆中的虚拟地址 4200,以及越过堆末端的 7 KiB。代码虚拟起点是 0,堆虚拟起点是 4096,物理基址分别为 32768 和 34816。

代码偏移为 100,合法,物理地址为 32768+100=3286832768+100=32868。堆偏移为 4200−4096=1044200-4096=104,合法,物理地址为 34816+104=3492034816+104=34920。7 KiB 地址的堆内偏移是 7168−4096=30727168-4096=3072,不小于段长 2048,必须先报错,不能把它加到基址后继续访问。

p.8–9旧PDF兼容图片误显响应时间式;已回查PPTX正文层,实际分别写100+32K=32868、104+34K=34920,与上述计算一致。图中的左右箭头连接的是同一个段内位置。段内偏移不是总等于虚拟地址,只有从虚拟 0 开始的段才碰巧如此。

p.11–12:地址最高位选段,低位选偏移

p.11 Explicit approach

Chop up the address space into segments based on the top few bits of virtual address.

Example: virtual address 4200 (01000001101000)

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

1   // get top 2 bits of 14-bit VA
2   Segment = (VirtualAddress & SEG_MASK) >> SEG_SHIFT
3   // now get offset
4   Offset = VirtualAddress & OFFSET_MASK
5   if (Offset >= Bounds[Segment])
6       RaiseException(PROTECTION_FAULT)
7   else
8       PhysAddr = Base[Segment] + Offset
9       Register = AccessMemory(PhysAddr)

课件题设是 14 位虚拟地址,最高 2 位为段号,低 12 位为偏移;4200 的二进制为 01 000001101000。因此段号为 1(Heap),偏移为 104。掩码 0x3000 取出最高两位,右移 12 位得到段号;0xFFF 取低十二位。

课件伪代码的逻辑是:提取段号与偏移,检查 Offset >= Bounds[Segment],合法才访问 Base[Segment]+Offset。低十二位允许编码 4096 个偏移,不表示该段实际分配了 4096 字节;本例只有 2048,剩余编码应被界限检查挡住。

p.13–15:栈增长方向与共享权限

p.13 Stack grows backward.

Extra hardware support is need.

The hardware checks which way the segment grows.

1: positive direction, 0: negative direction

p.13 Segment Register(with Negative-Growth Support)

p.14 Segment can be shared between address space.

Code sharing is still in use in systems today.

by extra hardware support.

Extra hardware support is need for form of Protection bits.

A few more bits per segment to indicate permissions of read, write and execute.

p.14 Segment Base Size Grows Positive? Protection

Code 32K 2K 1 Read-Execute

Heap 34K 2K 1 Read-Write

Stack 28K 2K 0 Read-Write

p.15 Coarse-Grained means segmentation in a small number.

e.g., code, heap, stack.

Fine-Grained segmentation allows more flexibility for address space in some early system.

To support many segments, Hardware support with a segment table is required.

图 p.13 为每个段增加增长方向:Code、Heap 向高地址,Stack 向低地址。对向下增长的段,不能直接套用正偏移加法而不作修正。补充算例:若一个 4 KiB 的虚拟段槽低十二位为 3996,则相对槽顶的偏移是 3996−4096=−1003996-4096=-100;用栈高端 28672 加它得到 28572。实际占用长度是 2048,应检查该负偏移是否落在允许区间。

p.14 的保护位使同一物理代码段可映射给多个进程,并赋 Read-Execute;数据段为 Read-Write。共享不是取消保护,而是让多个合法映射指向同一对象。p.15 区分粗粒度的少数段与细粒度的多段:段数多时需要段表,管理成本也上升。

补充:向下增长为什么先减虚拟槽大小。 高位段号先选中栈的虚拟槽,低12位只是从槽底数的位置,不是离栈顶的距离。槽大小4096,低位3996意味着距槽顶还差100,故有符号偏移为−100。若栈的物理高端是28672,得到28572;若误把3996直接加上去,得到32668,方向反了。

以2KiB实际栈长为例,合法负偏移为−2048到−1,对应物理区间[26624,28672)。偏移−2048仍是最后一个允许的低端字节;偏移−2049越界。这里采用课件高端为不包含端点的约定,不能把物理高端本身当成已分配栈中的一个字节。边界数值比“栈向下”口号更能检验是否理解。

自测:总空闲24KiB却放不下16KiB段,为什么改成分页可能解决?

分段要求这16KiB在一个连续物理区间,本图最大洞只有12KiB。固定页分页允许把多个页框分别放进不同空洞,虚拟连续不再要求物理连续。但仍须有足够的可用页框、页表存储和合法映射,分页没有凭空增加总内存。

p.16–17:外部碎片与压缩

p.16 External Fragmentation: little holes of free space in physical memory that make difficulty to allocate new segments.

There is X KB free, but not in one contiguous segment.

The OS cannot satisfy the X KB request.

Compaction: rearranging the exiting segments in physical memory.

Compaction is costly.

Stop running process.

Copy data to somewhere.

Change segment register value.

图 p.17 左边 OS 占 16 KiB,三个空洞分别为 [16,24)、[32,36)、[44,56) KiB(36、44 由相邻刻度间的中点读取),共 8+4+12=24 KiB,但最大单洞只有 12 KiB。16 KiB 连续段即使总空闲够也放不下。右边把占用段搬到一起,空闲合并为 [40,64) KiB,才形成 24 KiB 连续空间。

压缩需暂停或协调访问、复制数据并更新基址。分段避免了整片未用地址空间的浪费,却引入可变长区域的外部碎片;下一 Part 用固定大小页降低这种分配困难。

补充:压缩为什么不仅是把空闲数字加起来。 当总空闲足够而最大连续洞不足时,可以设想把已有段搬到相邻位置,将零散空洞合并。但搬动之后,旧物理基址已不再指向该段;系统必须相应更新段的映射信息,且不能让进程在搬到一半时按旧配置继续读写。可重定位的地址机制使这种移动成为可能,却不消除复制数据与协调执行的成本。

外部碎片发生在已分配区域之间的洞,内部碎片发生在已经分给某对象、对象却没用满的分配单元内部。前者导致“总空闲够,却找不到一整段”;后者导致“这部分空间属于某个分配单元,别的对象不能拿来用”。二者都浪费空间,但压紧已有段主要针对前一种,不能靠挪位置自动消除后一种。

本讲核心考点

  • [C] 给虚拟段起点、物理基址和长度,完成段选择、偏移与越界检查。
  • [C] 解释向下增长栈为何需要增长方向信息。
  • [C] 从空洞图计算总空闲与最大连续空闲,区分二者。

附录

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

来源与证据

  • 原件:L10-分段与分页-2022未核.pptx(本地课件);PDF副本(本地课件) p.1–17。本文页码均为 PDF 页号。

  • 教材:OSTEP 第 16 章(Segmentation),术语对应;本篇计算以课件数据为准。

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

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