Ondemand 按需分配导论
Ondemand 使用场景
IOCTL Ondemand 方式分配内存
MLOCK Ondemand 方式分配内存
MADVISE Ondemand 方式分配内存
Ondemand 按需分配导论
Ondemand 分配方式是用户进程分配虚拟内存的一种方式,进程分配内存时只分配虚拟内存,并不分配物理内存,然后进程可以控制何时分配物理内存的分配和页表的映射,那么当进程首次访问虚拟内存时就不会触发缺页。OnDemand 分配方式是 PreALLOC 分配方式和 LazyALLOC 分配方式的折中方案,其具有如下特点:
- 内存利用率高: 进程可以控制何时分配物理内存,那么可以更加做到按需分配内存,有利于内存的合理利用
- 降低启动成本: 按需分配在分配内存时只分配虚拟内存,并不分配物理内存,引起分配内存不会占用太多时间,有利于快速启动的场景
- 支持大内存空间: 允许分配大于物理内存大小的虚拟内存空间,从而为应用程序提供更大的地址空间
- 避免内存浪费: 如果程序分配了内存但未实际使用,按需分配避免了不必要的物理内存浪费
- 避免缺页异常的开销: 进程可以控制物理内存何时分配,那么可以确保进程首次访问虚拟内存时不发生缺页,有利于加速内存的访问
- 控制成本: 进程需要增加任务来控制何时为虚拟内存分配物理内存,需要比较精细的操作,容易出错.
因此开发者在选择Ondemand 分配方式之前需要对自己的场景充分考虑其带来的优点和缺点. 按需分配适合于特定的场景,例如提前向虚拟内存写入数据,或者按需分配物理内存等. 它可以有效地使用有限的物理内存资源,并提供灵活的内存管理, 并且对于性能敏感的应用程序,只要分配物理内存的时机掌握的好,那么可以大大加速进程对内存的访问速度。
Linux 里实现 OnDemand 分配方式的接口和方法比较多,只要符合在进程访问虚拟内存之前,为虚拟内存分配物理内存和建立页表的行为,都可以归类为 OnDemand 分配方式,整理以下几种情况:
- IOCTL 方式: 用户进程通过 ioctl 系统调用与模块进行交互,让内核模块为指定虚拟内存分配物理并建立页表,也可以向虚拟内存写入预设的数据,那么进程首次访问虚拟内存的时候就不会发生缺页,这将大大加速对内存的访问,同时仅在需要使用虚拟内存的时候才会分配物理内存,这也大大节约了物理内存。该方式在内核里使用很广,例如进程的堆栈创建过程等.
- MLOCK 方式: 用户进程通过 mlock 系统调用可以为虚拟内存分配物理内存和建立页表映射,mlock 的好处就是进程可以自主控制合适为虚拟内存分配物理内存.
- MADVISE 方式: 用户进程可以通过 madvise 系统调用建议内核对虚拟内存执行指定操作,其中支持 MADV_POPULATE_READ 请求,该请求会按读操作方式为虚拟内存分配物理内存并建立页表,MADV_POPULATE_WRITE 请求则按写操作方式为虚拟内存分配物理内存和建立页表。指的注意的是在支持 ZERO-PAGE 的场景下,MADV_POPULATE_READ 请求会将虚拟内存映射到 ZERO-PAGE 上,进程如果对虚拟内存发起写操作,同样会触发缺页,因此使用时需要根据 VMA 的属性进行使用.