段式虚拟存储器:一座“量身定制“的智慧大厦

📅 2026/6/18 16:13:22
段式虚拟存储器:一座“量身定制“的智慧大厦
楔子一个关于整理房间的哲学问题假设你要搬家面前堆着一大堆东西书籍、衣服、厨具、电子设备……有两种打包方式方式一拿来一堆完全相同的标准纸箱不管装的是什么每个箱子都装满固定的重量就封箱。于是一个箱子里可能既有书又有袜子还有半个炒锅。这种一刀切的打包法就是我们上一篇讲过的分页。方式二按照物品的种类来打包——书籍单独装、衣服单独装、厨具单独装。每一类东西用一个独立的箱子箱子大小根据物品多少来定书多就用大箱袜子少就用小箱。这种按意义分类的打包法就是今天的主角——分段。你有没有发现第二种方式更符合人类的直觉因为它尊重了物品本身的逻辑关系——同一类的东西放在一起找起来方便管理起来清晰。段式虚拟存储器正是这样一种懂得尊重程序逻辑的存储管理方式。让我们走进这座量身定制的智慧大厦看看它的精妙之处。第一章程序员眼中的世界——程序本就是分段的一个程序的内部结构在动手之前我们先思考一个问题一个程序在程序员眼里到底长什么样一个典型的程序并不是一团乱麻而是由几个逻辑清晰的功能模块组成的代码段主程序程序的指令告诉计算机做什么子程序段函数库被反复调用的功能模块数据段程序要处理的各种数据栈段用来存放函数调用、临时变量的草稿纸生动理解这就像一家公司天然地分成了研发部、市场部、财务部、后勤部。每个部门职能不同、人数不同但都是独立而完整的单元。你看程序本身就是分段的每一段都有它独立的意义和完整的功能。那么问题来了既然程序天然分段我们为什么非要像分页那样把它强行切成大小相等、毫无逻辑意义的碎块呢打个比方分页就像把公司所有员工不分部门每50人硬塞进一间办公室。结果研发部的人可能和财务部的人挤在一起一个完整的部门被拆散在好几个房间里。而分段则说让每个部门拥有自己独立的、大小合适的办公区域研发部人多就给大空间后勤部人少就给小空间。这就是分段的核心思想——按照逻辑模块来划分每段大小不固定量身定制。第二章什么是段——量身定制的空间不再整齐划一而是各取所需在段式存储中程序的逻辑地址空间被划分成若干个段Segment。每个段有两个鲜明的特点每个段对应一个完整的逻辑模块比如一个函数、一组数据每个段的长度可以不同取决于它实际需要多大空间对比记忆页大小固定如4KB由硬件决定不管内容段大小可变由程序逻辑决定尊重内容每个段内部地址是从0开始连续编号的。也就是说每个段都有自己独立的一套门牌号。生动场景想象一座写字楼里面有好几家公司。每家公司内部都是从1号工位开始编号的。研发公司有它的1号、2号工位市场公司也有它自己的1号、2号工位。各家公司的编号互不干扰自成体系。于是一个程序在分段后就变成了若干个独立的、长度不一的段每个段内部地址从0开始。第三章段式地址的双重身份——段号与段内偏移一个地址两个信息在段式存储中一个逻辑地址同样由两部分组成但含义和分页不太一样┌──────────────┬──────────────────┐ │ 段号 S │ 段内偏移 W │ └──────────────┴──────────────────┘段号S告诉你在哪一个段哪个部门段内偏移W告诉你在这个段内部的第几个位置这个部门的第几个工位生动理解这就像公司里的定位方式——“研发部·第27号工位”。研发部就是段号——告诉你去哪个部门第27号工位就是段内偏移——告诉你在那个部门里的具体位置注意一个关键区别在分页中因为每页大小固定逻辑地址是天然连续的页号和页内偏移是直接从一个二进制地址里切出来的。而在分段中因为每段长度不同逻辑地址需要明确地由段号和段内偏移两部分组成它们更像是程序员主动指定的段名位置。第四章段式世界的地址翻译官——段表一本记录每个部门在哪、有多大的档案和页式存储一样段也需要被搬进内存的某个位置。可问题是每个段大小不同被搬进内存后散落在内存的各个角落起始位置各不相同。程序说我要访问研发段的第27个位置可它不知道研发段被搬到了内存的哪里。这时又需要一位翻译官了——它就是段表Segment Table。段表是一张记录每个段详细信息的档案每一行每个段表项至少包含三样关键信息段号段长这个段有多大段基址这个段在内存的起始地址0号段代码2KB内存第8000号位置1号段数据5KB内存第3000号位置2号段栈1KB内存第15000号位置生动理解段表就像物业管理处的租户档案。它记录着“研发公司租了多大面积”段长“研发公司在大厦的哪个位置”段基址你要找研发公司的某个工位先查档案得知研发公司从8000号位置开始占地2KB然后就能精确定位了。注意段表项比页表项多了一个重要信息——段长这个段长可不是摆设它马上要派上大用场。第五章地址翻译全过程——一次带安检的寻址寻址五步曲含安全检查假设CPU要访问逻辑地址段号S段内偏移W完整的翻译过程如下第一步从逻辑地址中取出段号S和段内偏移W。第二步拿着段号S去查段表找到对应的段表项。第三步关键的安全检查比较段内偏移W和段长“你要访问的位置W有没有超出这个段的范围”如果W 段长合法访问放行通过 ✅如果W ≥ 段长越界了触发越界中断访问被拒绝 ❌第四步检查通过后从段表项中取出段基址B与段内偏移W相加物理地址 段基址B 段内偏移W第五步CPU拿着这个物理地址去内存对应位置取出数据寻址成功为什么要安检因为每个段都有明确的边界。研发部的工位只到第50号如果有人非要访问研发部的第99号工位那显然是出错了要么程序bug要么恶意攻击。段长的存在让系统能够精确地守护每一段的边界。这就像每个部门门口都有保安你刷卡进研发部但你要找的工位号超出了研发部的范围保安立刻拦住你“对不起您找的位置不在本部门不能放行”第六章分段的两大超能力——保护与共享段式存储有两个分页难以比拟的天然优势这都源于段对应完整逻辑模块这一特性。超能力一精细的安全保护️因为每个段是一个完整的逻辑单元我们可以给整个段设置统一的访问权限代码段设为只读 可执行防止程序运行时不小心把自己的指令改了数据段设为可读可写方便处理数据只读数据段设为只读保护常量不被篡改生动理解这就像给公司不同部门设置不同的门禁权限财务部只有财务人员能进高度保密接待大厅所有人都能进公开机房只能看不能动只读权限以部门段为单位清晰明了。如果用分页一个部门被拆在好几个箱子里权限管理就乱套了。超能力二方便的资源共享很多程序会用到相同的功能模块比如同一个函数库。在段式存储中多个程序可以共享同一个段生动场景假设大厦里有好几家公司它们都需要用到会议室。与其每家公司都自建一个会议室浪费空间不如大家共用一个公共会议室——只要在各自的档案段表里都指向同一个会议室的位置即可。同样一个被多个程序使用的函数库在内存里只需保存一份各个程序的段表都指向它。这样既省内存又便于维护。由于段是完整的逻辑模块共享起来干净利落——共享的就是一个完整的、有意义的单元而不是分页那种半个函数加半串数据的尴尬碎块。第七章美中不足——恼人的外部碎片段式存储如此优雅但它也有一个挥之不去的烦恼——外部碎片。大小不一带来的麻烦还记得吗每个段大小不同。当段被不断地调入、调出内存时间一长内存里就会出现许多大小不一的空闲小块它们零散地分布着每一块都不大单独拿出来谁也装不下一个完整的新段。生动场景想象一个停车场停的全是大小不同的车——大巴、轿车、卡车。车来车往开走几辆后停车场里东一块、西一块地空出了一些缝隙。可这些缝隙单独看每一个都太小停不下一辆新的大巴。但如果把它们加起来明明空间是够的这些用不上的零散空间就是外部碎片。这正是分段的痛点因为段长不固定内存分配后留下的边角料难以利用。对比分页就没有这个烦恼。因为页和页框大小完全相同任何一个空闲页框都能装下任何一页绝不会有装不下的尴尬分页只有少量内部碎片——最后一页可能没装满。解决办法紧凑技术为了对付外部碎片可以采用**紧凑Compaction**技术——把内存中分散的段重新挪动向一端集中让空闲空间连成一片大块。就像停车场管理员把所有车都往一边靠拢停齐于是零散的缝隙就合并成了一大片空地足以停下新来的大巴。但紧凑需要大量地搬移数据代价不小不能频繁使用。第八章段式 VS 页式——一场理念之争让我们把这两位存储管理大师放在一起做个全面对比对比维度页式存储段式存储划分依据硬件固定大小不管内容程序逻辑模块尊重内容大小固定如4KB可变按需而定划分者系统自动完成体现程序员的逻辑设计地址结构一维天然连续二维段号段内偏移碎片问题内部碎片少量浪费外部碎片需紧凑解决保护与共享不太方便非常方便、自然优点内存利用率高、管理简单符合逻辑、便于保护和共享一句话总结二者的哲学差异分页站在系统的角度我只管把内存用满至于你程序的逻辑结构我不关心。重效率轻逻辑。分段站在程序员的角度我尊重你程序的每一个逻辑模块让它们各得其所、方便保护和共享。重逻辑轻效率。那么有没有办法取二者之长避二者之短呢有那就是把分段和分页结合起来的——段页式存储管理。它先把程序按逻辑分成段满足逻辑性再把每个段切成固定大小的页解决碎片问题。不过那就是另一个精彩的故事了。尾声技术中的以人为本回顾段式虚拟存储器你会发现它身上闪耀着一种特别的光芒——它是以程序员为中心的设计。分页方便了机器而分段理解了人。它明白程序员心中的程序不是一团均匀的字节流而是一个个有血有肉、各司其职的逻辑模块它愿意为每个模块量身定制空间愿意为每个模块设置专属的保护愿意让有用的模块被大家共享。这种尊重逻辑、尊重结构的设计哲学启示我们一个朴素而深刻的道理最好的工具不是逼着人去适应机器而是让机器去贴合人的思维。当然段式存储也为这份以人为本付出了代价——外部碎片的烦恼正是它尊重逻辑、不愿一刀切的副作用。世上没有完美的方案每一个设计都是在取舍之间寻找平衡。而正是分页与分段各自的优劣催生了后来集大成的段页式——这恰恰说明技术的进步往往来自于对不同思想的融合与超越。下一次当你的程序在内存中优雅地运行每个模块安守本分、互不侵犯时请记得这背后有一种叫分段的智慧正默默地守护着秩序与逻辑之美。️✨核心知识点回顾概念一句话理解段按程序逻辑模块划分大小可变的存储块段号 段内偏移段式逻辑地址的两个组成部分段表记录每个段的段长和段基址的档案越界检查用段长检查访问是否超出段的边界地址翻译物理地址 段基址 段内偏移段的保护以段为单位设置访问权限段的共享多个程序共用同一个段省内存外部碎片段大小不一导致的零散空闲空间