首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >内存管理:分段、分页和段页式,到底咋回事?

内存管理:分段、分页和段页式,到底咋回事?

作者头像
码农UP2U
发布2026-03-16 18:19:07
发布2026-03-16 18:19:07
1170
举报
文章被收录于专栏:码农UP2U码农UP2U

每个时代有每个时代的生意,但是这些生意好像一直都没什么变化,比如之前的 IT 培训机构是让大家转行进入 IT 行业;后来这些 IT 培训机构是让大家进入大厂;再后来这些 IT 培训机构开始带你做副业;现在这些 IT 培训机构带你通过 AI 做副业。有些时候东西没啥变化,只是跟着市场和技术更新,噱头一直在变。

IT 浪潮开始了,就让你转行;大厂钱多,就带你进大厂;大厂不香了,就教你做副业;AI 火了,那么就靠 AI 做副业。

有人说好的生意是:简单 + 持续 + 门槛~!你觉得呢?

上面是调侃,下面是正文~!


接触过操作系统的都知道,内存的管理有分段管理、分页管理,还有段页式管理,但为啥要有这么多机制?它们是怎么来的?其实理解起来并不难,咱们从历史发展捋一捋就明白了。

0x01:直接访问物理地址

早期的处理器(比如 Intel 4004、8080)访问内存非常简单粗暴——直接用物理地址。那时候还没有“段”的概念,程序想访问哪就访问哪,没有任何限制,内存也就那么大,还能访问哪?

不过用过这些 CPU 的应该都是骨灰级的程序员了吧,可能就是发明 Unix、 Windows 的那些内核的骨灰级程序员了吧?

0x02:为什么要分段?

后来 Intel 出了 8086,是 16 位处理器,但地址总线是 20 位。这就尴尬了:16 位的寄存器怎么表示 20 位的地址?

于是 Intel 想了个办法:引入“分段”机制。用 “段基地址 + 段内偏移” 来合成一个 20 位的地址。具体做法是:段基地址左移 4 位(相当于乘以 0x10),再加上偏移量

比如要访问 0x7c00 这个地址,可以设段基地址为 0x07c0,偏移量为 0x0000,一拼就成了。很神奇!

这个 CPU 只要是科班出身的,或者学习过汇编语言的都应该知道了。

再补充一句,都说学校学的知识旧,就说学汇编这个东西,首先它的知识不旧,其次,学汇编入门估计绕不开这个 8086 CPU 吧。

0x03:保护模式:分段也开始讲权限了

通过上面的方式,16 位的寄存器能访问 1MB 的内存了。但这个时候还没有权限检查,程序之间可以随便互相访问内存,非常不安全。

我们学 16 位汇编的时候,都干过修改 DOS 的中断向量是吧~!!

到了 80286,Intel 引入了 “保护模式”。不再是随便访问内存了,CPU 会检查权限。

段寄存器里不再直接放段基地址,而是放一个叫 “选择子” 的东西,它相当于一个索引,指向一个叫 “段描述符” 的结构,里面记录了段的基地址、长度和权限等信息。

CPU 在访问内存时会检查当前程序有没有权限访问目标地址,如果没有就直接拒绝。这就实现了内存保护。

虽然是从 80286 开始的,但是大部分接触保护模式都是学习的 80386 的 CPU 了。因为 80286 的保护模式不太成熟,估计真正用过的也是那个时代的程序员了,我们应该是学过 8086 后,跳过 80286 直接进入 80386 了。Linux 的第一个版本也是基于 80386 的!

0x04:分页又是什么?为什么需要它?

虽然分段解决了寻址和保护的问题,但它有个大问题:管理粒度太粗。一个段可能很大,容易产生内存碎片。

举个例子:假如你的内存有 128MB 的空间,你开了几个应用后还剩下一些内存空间,但是由于内存有碎片的关系,而导致内存空间明明够,但是却无法直接容纳比剩余空间小的应用了。

128MB 的内存很大,不知道你觉得不?

这时候就得把某个程序整个挪到硬盘上,再把零散空间合并,才能加载新程序。但硬盘速度慢,整体交换效率很低。

所以,80386 处理器引入了分页机制:把内存分成固定大小的“页”(一般 4KB),按页来管理。程序不用整个加载进内存,用哪页加载哪页。CPU 访问到不存在的页时,依靠缺页中断加载缺失的页面就行。

这样一来,内存利用率高了,碎片少了,交换效率也提升了。同时,分页还实现了 “虚拟内存” ——让每个进程都觉得自己独享整个内存空间,背后实际是通过页表把虚拟地址映射到物理地址。

0x05:段页式:为啥要俩一起用?

到了 32 位时代(比如 80386),寄存器已经是 32 位,光靠偏移量就能访问 4GB 内存,分段其实已经没必要了。但为了兼容老程序,分段机制还是保留了下来。

于是很多系统(比如 Linux、Windows)就把所有的段基地址都设为 0,偏移量直接当线性地址用——相当于“绕过”了分段。相当于把所有的内存划分了一个段。

然后再在这个线性地址基础上做分页转换,得到真正的物理地址。这就是“段页式”内存管理:先分段(但基本是形式),再分页。

到了 64 位 CPU 的时候,段的概念还是在的,但是段的基址和界限这个概念就被忽略了,而页的级别的就更多了。

0x06:总结一下:

  • 分段最初是为了解决 16 位 CPU 访问 20 位内存的问题,后来加上了权限保护。
  • 分页是为了更精细地管理内存,减少碎片,提高利用率和交换效率。
  • 段页式是历史兼容 + 现代需求的结合体:形式上保留分段,实际靠分页干活。

这些机制都不是凭空硬造的,而是一步步发展出来的自然结果。就像很多牛人说的,火车的宽度是两个马屁股的宽度。

在 CPU 发展过程中引入了好几个用于内存管理的寄存器,比如 CS DS SS ES FS GS,比如 GDTR、比如 CR3…这些都是程序员可以使用的东西哦!

都看到这里,给点个赞支持一下再走吧~!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-09-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 源代码010 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档