图片无法显示,请右键点击新窗口打开图片

BiscuitOS 内存管理之分页大专题订阅入口

目录

  • 初识 PageFault

  • PageFault 导论

    • 缺页数据结构逻辑

    • Page Fault Exception

    • PageFault With ERROR Code

    • PageTable With PageFault

    • PageFault Event 统计

    • Page Fault Handlers Reason

  • PageFault on Architecture

    • PageFault on Intl X86

    • PageFault on ARM/ARM64(未来可期)

    • PageFault on RISCV(未来可期)

  • PageFault on Kernel

  • PageFault on Userspace

    • 匿名内存(Anonymous) With PageFault

      • 匿名映射可读可写内存缺页场景

      • 匿名映射只读(Read-Only)内存缺页场景

      • 匿名映射写保护(Write-Protection)内存缺页场景

      • 匿名映射 COW(Copy-On-Write) 内存缺页场景

      • 匿名映射内存交换(SWAP) 缺页场景

      • 匿名映射内存压缩(ZSWAP) 缺页场景

      • 匿名映射内存 KSM 缺页场景

      • 匿名映射内存 NUMA Balancing 缺页场景

      • 匿名映射内存 MCE 缺页场景

      • 匿名映射之堆(Heap) 缺页场景

      • 匿名映射之栈(Stack) 缺页场景

      • 匿名映射内存 Protection Key 缺页场景

      • 匿名映射之 PmdMapped THP 内存缺页场景

    • 共享内存(Shmem) With PageFault

      • 可读可写共享内存(R/W Shmem) 缺页场景

      • 只读共享内存(RO Shmem) 缺页场景

      • 共享内存 Fork 缺页场景

      • 共享内存换入换出(SWAP) 缺页场景

      • 共享内存内存压缩(ZSWAP) 缺页场景

      • 共享内存发生 MCE(UE) 缺页场景

      • 共享内存 SYSV 缺页场景

      • 共享内存 POSIX 缺页场景

      • 共享内存 UNIX-SOCK 缺页场景

      • 共享内存 MEMFD 缺页场景

      • 共享内存 DEV-SHM 缺页场景

      • 共享内存 LOCAL 缺页场景

      • 共享内存 HugeShmem(THP) 缺页场景

      • 共享内存 Protection Key 缺页场景

    • File-Mapped With PageFault

      • MINIXFS 文件系统缺页场景

      • EXT2 文件系统缺页场景

      • EXT3 文件系统缺页场景

      • EXT4 文件系统缺页场景

      • VFAT 文件系统缺页场景

      • MSDOS 文件系统缺页场景

      • FAT 文件系统缺页场景

      • CRAMFS 文件系统缺页场景

      • BFS 文件系统缺页场景

      • JFFS2 文件系统缺页场景

      • UBIFS 文件系统缺页场景

      • SQUASHFS 文件系统缺页场景

      • BTRFS 文件系统缺页场景

      • REISERFS 文件系统缺页场景

      • JFS 文件系统缺页场景

      • XFS 文件系统缺页场景

      • GFS2 文件系统缺页场景

      • F2FS 文件系统缺页场景

      • TMPFS 文件系统缺页场景

      • Huge-Tmpfs 文件系统缺页场景

      • XFS DAX 缺页场景

    • PFNMAP With PageFault

      • PFNMAP 映射 可读写 RSVDMEM 内存场景

      • PFNMAP 映射 只读(Read-Only) RSVDMEM 内存场景

      • PFNMAP 映射 写保护(Write-Protection) RSVDMEM 内存场景

      • PFNMAP 映射 PudMapped 2MiB RSVDMEM 内存场景

      • PFNMAP 映射 PudMapped 1Gig RSVDMEM 内存场景

    • HUGE Page Fault

      • Huge-PageFault: 可读可写透明大页场景

      • Huge-PageFault: 只读透明大页场景

      • Huge-PageFault: 写保护透明大页场景

      • Huge-PageFault: COW 透明大页场景

      • Huge-PageFault: NUMA Balancing 透明大页场景

      • Huge-PageFault: EXT4 DAX 文件透明大页场景

      • Huge-PageFault: XFS DAX 文件透明大页场景

      • Huge-PageFault: PUD HUGE FAULT 场景

    • HugeTLB Page With PageFault

      • HugeTLB Memory: R/W 缺页场景

      • HugeTLB Memory: WP 缺页场景

      • HugeTLB Memory: COW 缺页场景

      • HugeTLB Memory: 不同粒度 HugeTLB 缺页场景

      • HugeTLB Memory: SYSV 缺页场景

      • HugeTLB Memory: POSIX 缺页场景

      • HugeTLB Memory: MEMFD 缺页场景

      • HugeTLB Memory: MCE(UE) 故障缺页场景

      • HugeTLB Memory: OOM 大页内存不足缺页场景

      • HugeTLB Memory: Surplus 超发大页缺页场景

  • PageFault 机制实践

  • PageFault 机制使用

  • PageFault 与工程落地

  • Tools for PageFault

    • 使用 BiscuitOS 观测缺页流程

    • Kdump/Crash with PageFault

  • PageFault 源码分析

  • PageFault 进阶研究

    • PageFault Exception Reason

    • PageFault Handlers Reason

    • SWAP with PageFault

    • COW with PageFault

    • SegmentFault/SIG_BUS on PageFault

    • Migration with PageFault

    • MCE(UE) with PageFault

    • NUMA Balancing with PageFault

    • KSM with PageFault

    • Memory Compress/Decompress(ZSWAP) with PageFault

    • COPY-USER with PageFault

    • HMM 异构内存缺页(技术攻坚中)

    • IOMMU 缺页

    • PMEM DAX With PageFault

    • 虚拟化 EPT TDP PageFault

    • 逆向映射/反向映射(Reverse-Mapping)与缺页

    • STRUCT address_space 与缺页

    • Protection Key(PKRU) With PageFault

    • Userfaultfd(用户空间缺页)

    • Write Protection with PageFault

    • MMAP_LOTSAMISS

    • 如何区分 ZERO Page 与 COW 的 Write-Protection

图片无法显示,请右键点击新窗口打开图片


PageFault 导论

图片无法显示,请右键点击新窗口打开图片

在 Linux 内存管理里,开启分页之后,CPU 直接访问的虚拟内存,虚拟内存与物理内存之间建立页表,那么 CPU 才能正常访问虚拟内存. 当虚拟内存没有与物理内存建立页表之前,CPU 就访问这段虚拟内存会引起异常(Exception), 在 Linux 里将这个异常称为缺页异常(Page Fault Exception), Linux 为缺页异常设置了缺页异常处理函数(或缺页中断处理函数). 缺页异常处理函数的主要任务是在合理的请求下,为虚拟内存分配物理内存,然后建立虚拟内存到物理内存的页表,并在缺页异常处理函数返回之后重新执行发生异常的指令, 那么 CPU 可以继续访问虚拟内存.

图片无法显示,请右键点击新窗口打开图片

进程分配内存的方式有三种,三种方式虽然不同,但只有建立了虚拟内存到物理内存的页表之后,CPU 才可以访问,三种分配方式的特点如下:

  • PreAlloc(预分配): 即进程分配虚拟内存的同时也分配物理内存,并建立虚拟内存到物理内存之间的页表,因此这类型的内存不会发生缺页,例如 malloc() 函数分配的小粒度内存,或者 mmap() 函数添加了 MAP_POPULATE 标志. 由于其分配特点,存在分配内存时会消耗很多时间,另外分配多少虚拟内存就会分配多少虚拟内存,那么可能会造成内存浪费,一旦内存分配好,那么 CPU 初次访问内存时速度会比缺页的快很多,因此这种方式适合对运行时内存访问速度要求高的场景.
  • LazyAlloc(惰性分配): 即进程起初只分配虚拟内存,只有当 CPU 访问虚拟内存时,触发缺页异常之后,缺页中断为其分配物理内存并建立页表,在缺页中断返回之后再次执行发送异常的指令,例如使用 mmap() 函数不带 MAP_POPULATE 标志分配内存,或者 malloc 分配大粒度内存. 由于其特点,存在分配内存时速度很快,并只有用到才会去分配内存,因此很节省内存,但是 CPU 初次访问内存会触发缺页相当耗时,因此这种方式适合内存资源紧缺的场景.
  • On-Demand(按需分配): 即进程起初只分配虚拟内存,但进程觉得需要为虚拟内存分配物理内存时,那么会为虚拟内存分配物理内存并建立页表,这样 CPU 访问内存时不会发送缺页异常。例如 GUP(Get User Page) 机制 或者 madvise 机制的 MADV_HUGEPAGE 请求。由于其特点,存在分配内存时速度很快,初次访问时无需缺页就可以访问,访问速度很快,但需要进程介入控制分配.

无论是使用何种分配方式,需要借助缺页机制来分配物理内存和建立页表,只是 LazyAlloc 会触发缺页异常完成物理内存分配和页表建立,而 PreAllocOn-Demand 会主动调用缺页机制提供的接口,以此完成物理内存的分配和页表建立. 因此开发者在学习缺页机制时候一定要记住的一个定理: 什么时候分配物理内存,什么时候建立页表.

Page Fault Exception

图片无法显示,请右键点击新窗口打开图片

页面错误异常(Page Fault Exception) 是当 CPU 尝试访问一个当前不在物理内存中的虚拟页时,由内存管理单元(MMU)触发的异常。此异常可能是由于该页尚未加载到 RAM、访问违规,或者对应的页表条目无效所引起的. 缺页异常发送之后,不同架构会给出发生异常的原因. 例如 Intel X86 架构会提供上图引起缺页异常的原因,其他架构与之类似:

  • PRSENT: 由于虚拟内存没有映射物理内存引起的页面故障
  • READ: 对虚拟区域写操作引起的页面故障
  • WRITE: 对写保护的虚拟区域执行写操作引起的页面故障
  • User: 缺页故障发生在用户空间
  • Super: 缺页故障发生在内核空间
  • Instruct: 缺页故障由执行指令引起的页面故障

图片无法显示,请右键点击新窗口打开图片

缺页异常在给出故障原因的同时,也会给出发生缺页的虚拟地址。例如在 Intel X86 架构下,当发生缺页异常时,CR2 寄存器存储了发生缺页的虚拟地址,然后结合当前进程和虚拟地址,缺页异常处理函数可以找到对应的 VMA.

图片无法显示,请右键点击新窗口打开图片

图片无法显示,请右键点击新窗口打开图片

BiscuitOS 内存管理之分页大专题订阅入口

图片无法显示,请右键点击新窗口打开图片