Skip to content

方法Method

物理页分配与安全回收

Physical page allocator · Page frame free list

把页框所有权、空闲链、发布前清零和最后使用者释放串成分配协议,解释它与用户堆对象分配的不同粒度。

形式陈述 ​

物理页分配器管理一组等长页框。OS-16将内核保留页表帧与可分配数据帧分开;每个数据帧恰属于FREE或ALLOCATED之一;已分配帧附有持有者集合,PINNED是可与用户映射同时成立的回收资格标记,不是互斥的第三种所有权。空闲链F只能含FREE帧且无重复。alloc取出一个帧并转为私有内核所有;调用者初始化后才能发布用户PTE。free只接受没有用户映射、没有内核持有者、没有未完成设备引用的已分配帧。

对含COW映射的子池,mapcount记录用户PTE数;对设备使用的帧另有pincount。可回收条件为

mapcount=0 ∧ pincount=0 ∧ 无其他所有者和在途使用.

等式左边任一项为零都不单独充分。匿名页首次发布前清零,文件页首次发布前从正确backing读取;分配器本身不需要把两者都定义成零页。

使用单链表时,受保护地移除表头和插回表头可为O(1)。清零B字节为O(B),空间清理、等待pin释放或物理连续多页的搜寻是另计成本。多核上链头与状态更新需要原子协议或锁,不能让两个CPU同时取得同一帧。

直觉

页框分配器给内核一整块内存,语言运行时再把已取得的区域切成对象。用户调用一次小对象分配,不必每次陷入内核;内核新增一个256B页,也不意味着里面只有一个对象。两层分配器管理不同所有权边界。

回收的关键不是“程序说不用了”,而是所有能继续访问该帧的路径都已消失。一个PTE被删除后若TLB还缓存着它,或设备仍按旧DMA描述符写入,帧就还没有真正脱离旧使用者。

例子与边界

四个动作维护自由集合 ​

OS-16数据空闲链最初为[0x60,0x61,0x62]。P的合法缺页取走0x60,链变[0x61,0x62];清零256B后发布PTE,mapcount[0x60]=1。P fork C让mapcount升为2,但不再取页。C解除该映射后mapcount降到1,仍不能把0x60放回链;P也解除、完成TLB失效后计数为0,才把0x60插回链头。

假设两进程都已解除映射,但设备读取0x60的DMA尚未完成,pincount=1。若此时重分配给Q并清零,设备就可能读到Q的新数据或清零结果,而非提交时的旧缓冲。等待设备完成并解除pin后才可回收,避免跨对象的晚到访问。

重复释放的实际后果 ​

错误地把0x60连续插入空闲链两次,会让后续两次alloc都返回0x60。两个调用者都认为自己独占,写入相互覆盖。给空闲帧填固定“毒化”字节有助于测试,却不能代替状态检查;它检测不到所有重复释放,也不能阻止别名分配。

若进程只请求1B但区域必须按256B页建立,最多255B暂时未被应用使用。这是页粒度内部碎片;用户堆分配器可以把多个小对象放在同页改善利用率。要求两个连续页却只有两个不相邻空闲帧,则是连续性要求与外部碎片问题,不能用“总空闲字节足够”解决。

推论与应用

设数据池共有N帧,把每帧分到空闲集合F或已分配集合A,二者应互斥且并集恰为池;同一已分配帧的持有者集合允许包含多个进程。alloc把一个元素从F转出,free按前置条件转回,归纳保持守恒;发布映射增加mapcount,撤销完成后减少它。若mapcount与实际PTE数量不一致,不能仅修数字而忽略仍存在的映射。

堆对象布局与分配已经给出对象头、描述符、对齐和快速分配,不在此重复。OS分配的是物理页及映射支持;运行时回收的是语义可达对象。某对象free后,它所在页仍可能含其他对象,因此物理页数未必立即下降。

在真实系统中,页引用还可能包含页缓存、映射、内核临时引用和设备pin,计数语义往往比本例复杂。必须先声明计数覆盖哪些持有者,再使用“减到零即释放”;单一数字的名字不是安全证明。

参考资料
  • Cox、Kaashoek、Morris,xv6教材 rev5,§3.4–3.5,页粒度free list及分配/释放。
  • Linux Kernel Documentation,pin_user_pages,2026-10-08核查,DMA pin与普通页面引用的用途区分;本页不照搬其实际计数编码。
关系图谱8 个相邻概念 · 1 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组