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

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

目录
  • PreALLOC 预分配导论

  • PreALLOC 使用场景

    • PreALLOC 方式分配匿名内存

    • PreALLOC 方式分配共享内存

    • PreALLOC 方式分配文件映射内存

    • PreALLOC 方式分配 PFNMAP 映射内存

    • PreALLOC 方式分配 MMIO 映射内存

    • PreALLOC 方式分配 DMA 内存

    • PreALLOC 方式分配 VMALLOC 内存

    • PreALLOC 方式分配透明大页内存

    • PreALLOC 方式分配 HugeTLB 大页内存

    • PreALLOC 方式分配 DAX 内存


PreALLOC 预分配导论

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

PreALLOC 分配方式是用户进程分配虚拟内存的一种方式,其在分配虚拟内存的时候同时也将物理内存分配好,并建立好页表映射,那么当进程访问虚拟内存时都会以最快的速度进行访问. 相比于惰性分配方式,PreALLOC 分配方式分配的虚拟内存并不会引起缺页. 与惰性内存分配相比,其具有如下特点:

  • 即时可用性: 分配后的内存立即可用,无需等待后续的缺页处理,这在需要快速访问内存的情况下是有利的
  • 确定性: 由于物理内存已经分配,因此减少了因内存不足而无法分配的风险, 这在内存需求可预测且稳定的环境下是一个优点
  • 性能: 避免了运行时的缺页处理开销, 缺页(PageFault)处理可能涉及到复杂的内存管理操作,预先分配可以减少这些操作,从而提高性能
  • 内存利用率: 可能导致内存利用率降低,特别是在分配了但长时间未使用的内存情况下, 这在内存资源紧张的系统中可能成为一个问题
  • 启动延迟: 程序启动时需要分配和初始化所有预先分配的内存,可能会导致启动延迟
  • 内存碎片: 长期运行的程序可能导致物理内存碎片化,特别是在频繁申请和释放大块内存的场景下
  • 扩展性问题: 对于需要大量内存的应用,预先分配可能导致无法满足需求,特别是在内存受限的环境中

因此开发者在选择PreALLOC 分配方式之前需要对自己的场景充分考虑其带来的优点和缺点. 在内存充足且对性能有高要求的环境下,预先分配是一种合理的选择. 然而在内存紧张或应用具有不确定的内存使用模式的情况下,可能更倾向于使用惰性分配的方式.

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

Linux 提供的 mmap 系统调用可以实现 PreALLOC 分配方式重要接口, 应用程序可以使用该接口为其分配虚拟内存,同时也分配物理内存,最终建立页表映射到物理内存上. mmap 系统调用为了能够实现 PreAlloc 方式的分配虚拟内存,那么 6 个参数应该按如下要求进行设置:

  • 参数一: 该参数可以设置从进程地址空间的指定位置分配虚拟内存,如果应用程序有这个需求可以通过该参数实现.
  • 参数二: 该参数用于设置分配虚拟内存的大小
  • 参数三: 该参数用于设置虚拟内存的访问权限,目前支持 PROT_READ、PROT_WRITE、PROT_EXEC, 三者可以混合搭配使用,也支持 PROT_NONE 将虚拟内存设置为即不可读也不可写, 但这些搭配也要符合系统的要求.
  • 参数四: 该参数用于选择虚拟内存的映射方式和特殊需求,参数通过指定的标志进行选择,例如 MAP_SHARED 表示采用共享映射、MAP_PRIVATE 表示采用匿名映射等,对于 PreALLOC 最重要的标志是 MAP_POPULATE, 也就是进程想分配 PreALLOC 的内存就必须带该标志.
  • 参数五: 当虚拟内存用于映射文件,那么需要将文件的 FD 填入该位置,否则该参数保持 “-1”.
  • 参数六: 该虚拟内存需要映射到指定物理区域时,可以将指定物理区域的起始地址填入到该位置; 反之如果支持映射到随机的物理页上,那么该参数设置为 0.

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

PreALLOC分配的虚拟内存支持映射到多种物理区域上,有的可以通过采用合适的 mmap 参数就可以实现,有的需要借助特殊系统提供的文件,有的则需要设备驱动提供专门的接口,但无论采用何种接口都需要 mmap 系统调用完成,那么对于不同类型的物理内存其在预分配场景下,mmap 的参数逻辑如下:

  • OSMEM: 对于映射系统管理的物理内存,只需在 mmap 系统调用里采用 MAP_POPULATE 标志即可, 其他参数任意
  • RSVDMEM: 对于映射系统预留物理内存,需要通过 “/dev/mem” 文件或者设备驱动提供的特殊文件实现,mmap 系统调用无需采用 MAP_POPULATE 标志,由于是通过文件映射的方式,因此不能采用 MAP_ANONYMOUS 标志.
  • MMIO: 对于映射 MMIO 区域,需要通过 “/dev/mem” 文件或者设备驱动提供的特殊文件实现,mmap 系统调用无需采用 MAP_POPULATE 标志,由于是通过文件映射的方式,因此不能采用 MAP_ANONYMOUS 标志.
  • PMEM: 对于映射 PMEM 内存,需要采用 DAX 方式进行映射,因此需要借助特殊的文件系统和文件,mmap 系统调用需要采用 MAP_POPULATE 标志,另外由于通过文件映射的方式,因此不能采用 MAP_ANONYMOUS 标志.
  • HUGELTB: 对于映射 HUGETLB 物理大页,可以通过匿名的方式映射 HUGETLB 大页,那么需要添加 MAP_ANONYMOUS 和 MAP_HUGETLB 标志; 反之如果通过 Hugetlbfs 文件系统的方式映射 HUGETLB 大页,那么需要打开指定的文件即可. 无论采用哪一种映射 HUGETLB 物理大页,如果采用 PreALLOC 方式分配内存时,需要采用 MAP_POPULATE 标志.
  • THP: 对于映射透明大页,由于 THP 有很多中类型,这里以匿名透明大页为例进行说明,需要采用 MAP_ANONYMOUS 和 MAP_PRIVATE 标志,另外虚拟内存大小要超过 2MiB,并且如果指定虚拟地址,那么虚拟地址也要按 2MiB 对齐,最后就是采用 PreALLOC 方式映射就需要带上 MAP_POPULATE 标志.
  • VMALLOC: VMALLOC 分配的内存可以与用户进程实现共享,那么用户进程需要基于私有的驱动模块来实现 VMALLOC 的映射,此时驱动模块会提供相应的文件,因此不能带有 MAP_ANONYMOUS 标志,另外也不需要带上 MAP_POPULATE 标志就可以实现预分配,这个操作有私有的驱动负责预分配的动作.
  • DMA: DMA 内存的特点就是大块连续的物理内存,因此进程可以借助私有驱动程序将 DMA 内存映射到进程地址空间,并且驱动负责实现预分配的操作,因此 mmap 不能带 MAP_ANONYMOUS 和 MAP_POPULATE 标志.
  • PAGECACHE: PAGECACHE 其实对应的是文件映射,由于文件映射的特点,因此不能待 MAP_ANONYMOUS 标志,文件映射为了实现预分配需要带上 MAP_POPULATE.
  • SHMEM: 共享内存支持文件映射方式和匿名方式进行映射,当使用匿名方式时需要带上 MAP_SHARED 和 MAP_ANONYMOUS 标志,而对于文件映射方式则仅仅带上 MAP_SHARED 标志即可。共享内存为了实现预分配,那么只需带上 MAP_POPULATE 即可.

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

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

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

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