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

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

目录
  • LazyALLOC 惰性分配导论

  • LazyALLOC 使用场景

    • LazyALLOC 方式分配匿名内存

    • LazyALLOC 方式分配共享内存

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

    • LazyALLOC 方式分配 PFNMAP 映射内存

    • LazyALLOC 方式分配 MMIO 映射内存

    • LazyALLOC 方式分配 DMA 内存

    • LazyALLOC 方式分配 VMALLOC 内存

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

    • LazyALLOC 方式分配 HugeTLB 大页内存

    • LazyALLOC 方式分配 DAX 内存


LazyALLOC 惰性分配导论

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

LazyALLOC 分配方式是用户进程分配虚拟内存的一种方式,其在分配时只分配虚拟内存,并不分配虚拟内存,而是进程首次访问虚拟内存时通过触发缺页异常,缺页异常处理函数负责分配物理内存和建立页表映射,待缺页异常处理返回之后,进程再次执行发生缺页异常的指令,此时进程可以正确访问虚拟内存. 与预分配内存相比,其具有如下特点:

  • 内存利用率高: 由于物理内存只在实际需要时才分配,这提高了内存的整体利用率, 不会为未使用的内存区域占用物理资源
  • 降低启动成本: 应用程序启动时,由于不需要立即分配所有内存,因此可以减少启动延迟
  • 支持大内存空间: 允许分配大于物理内存大小的虚拟内存空间,从而为应用程序提供更大的地址空间
  • 避免内存浪费: 如果程序分配了内存但未实际使用,惰性分配避免了不必要的物理内存浪费
  • 缺页异常的开销: 每次物理内存分配都需要处理缺页异常,这可能会增加运行时的性能开销,特别是在内存频繁访问的情况下
  • 延迟性能问题: 当程序访问未映射的内存时,会触发缺页异常,导致运行时延迟,可能影响性能
  • 内存分配不确定性: 在物理内存紧张的情况下,可能无法满足后续的内存请求,导致内存分配失败
  • 交换空间依赖: 在物理内存不足时,系统可能需要使用交换空间(Swap Space),这可能导致显著的性能下降

因此开发者在选择LazyALLOC 分配方式之前需要对自己的场景充分考虑其带来的优点和缺点. 惰性分配适用于多数普通应用程序,特别是那些内存使用模式不确定或分布广泛的情况。它可以有效地使用有限的物理内存资源,并提供灵活的内存管理。然而对于性能敏感的应用程序,特别是那些对延迟有严格要求的情况,可能需要考虑更精细的内存管理策略,以减少缺页异常处理的开销.

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

Linux 提供的 mmap 系统调用可以实现 LazyALLOC 分配方式重要接口, 应用程序可以使用该接口为其分配虚拟内存,但不分配物理内存,只有进程首次访问虚拟内存时,才通过缺页异常处理函数分配物理内存和建立页表. mmap 系统调用为了能够实现 LazyALLOC 方式的分配虚拟内存,那么 6 个参数应该按如下要求进行设置:

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

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

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

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

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

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

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