16 KB 页面大小

页面大小是操作系统管理内存的粒度。如今,大多数 CPU 都支持 4 KB 页面大小,因此 Android 操作系统和应用程序历来都是构建和优化为以 4 KB 页面大小运行的。ARM CPU 支持更大的 16 KB 页面大小,并且从 Android 15 开始,AOSP 也支持使用 16 KB 页面大小构建 Android。此选项会使用更多内存,但可以提高系统性能。截至 Android 15,此选项默认情况下未启用,但它作为开发者模式或 OEM 和应用开发者的开发者选项提供,以便为将来在所有地方切换到 16 KB 模式做好准备。

Android 15 及更高版本支持使用 16 KB ELF 对齐构建 Android,这适用于从 android14-6.1 开始的 4 KB 和 16 KB 内核。当与 16 KB 内核结合使用时,此配置会使用更多内存,但可以提高系统性能。

将 Android 用户空间设置为 16 KB

16 KB 页面仅在具有 16 KB 内核的 arm64 目标上受支持。但是,也可以选择在 Cuttlefish 上模拟 x86_64 上的 16 KB 用户空间

对于 arm64 目标,如果您使用 Kleaf 构建内核,则 --page_size=16k 会以 16 KB 模式构建内核。如果您直接使用 Linux 内核配置,则可以通过设置 CONFIG_ARM64_16K_PAGES 而不是 CONFIG_ARM64_4K_PAGES 来选择 16 KB 页面。

要在 Android 用户空间中启用 16 KB 页面大小支持,请在您的产品上设置以下构建选项

  • PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true 会移除 PAGE_SIZE define,并使组件在运行时确定页面大小。
  • PRODUCT_MAX_PAGE_SIZE_SUPPORTED := 16384,这可确保平台 ELF 文件以 16 KB 对齐方式构建。这种大于所需的大小是为了未来的兼容性。借助 16 KB ELF 对齐,内核可以支持 4 KB/16 KB 页面大小。

验证构建标志

选择 lunch 目标后,验证构建标志是否在环境中正确设置

$ source build/envsetup.sh
$ lunch target

$ get_build_var TARGET_MAX_PAGE_SIZE_SUPPORTED
16384
$ get_build_var TARGET_NO_BIONIC_PAGE_SIZE_MACRO
true

如果前两个命令分别返回 16384true,则您的构建标志已正确设置为使用 16 KB 内核。但是,即使构建通过,由于 16 KB 环境中的差异,仍可能存在运行时问题。

16 KB 页面大小系统编程

任何 Android 设备上的绝大多数代码都不会直接处理页面大小。但是,对于处理页面的代码,内核的内存分配行为会发生变化,您需要牢记这一点来编写代码,以使其不仅兼容,而且性能最高且资源密集度最低。

如果您在 4 KB 系统上对 1 KB、2 KB 或最大 4 KB 的区域调用 mmap,系统会保留 4 KB 来实现此操作。换句话说,当从内核请求内存时,内核必须始终将请求的内存向上舍入到最接近的页面大小。例如,如果您在 4 KB 区域上分配 5 KB 区域,则内核会分配 8 KB。

在 16 KB 内核上,页面的这些额外的“尾端”更大。例如,所有这些分配(从 1 KB 到 5 KB)在使用 16 KB 内核时都会分配 16 KB。如果您请求 17 KB,它会分配 32 KB。

例如,在 4 KB 系统上,可以分配两个 4 KB 读写匿名区域。但是,在 16 KB 内核上,这将导致分配两个页面或 32 KB。在 16 KB 内核上,如果可能,可以将这些区域合并到单个可读或可写页面中,这样就只会使用 16 KB,与 4 KB 内核情况相比,浪费了 8 KB。为了减少更多内存使用量,可以合并更多页面。事实上,在经过最大程度优化的 16 KB 系统上,16 KB 页面比 4 KB 系统需要更少的内存,因为对于相同的内存,页表的大小是四分之一。

无论何时使用 mmap,请确保将您请求的大小向上舍入到最接近的页面大小。这确保了内核分配的全部内存在运行时值中对用户空间直接可见,而不是被隐式请求和隐式或意外地访问。

使用 16 KB ELF 对齐构建共享库

要构建属于 android 项目的共享库,启用 16 KB 页面大小中的较早设置就足够了

  • PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true
  • PRODUCT_MAX_PAGE_SIZE_SUPPORTED := 16384

要构建不属于 android 项目的共享库,您需要传递此链接器标志

-Wl,-z,max-page-size=16384

验证二进制文件和预编译文件是否为 16 KB ELF 对齐

验证对齐和运行时行为的最佳方法是在 16 KB 编译内核上进行测试和运行。但是,为了更早地发现一些问题

  • 从 Android 16(AOSP 实验版)开始,您可以在构建时设置 PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE := true。在 Android.bp 中使用 ignore_max_page_size: true,在 Android.mk 中使用 LOCAL_IGNORE_MAX_PAGE_SIZE := true 可以暂时忽略它们。这些设置会验证所有预编译文件,并允许您检测到何时更新了某个预编译文件但未进行 16 KB 对齐。

  • 您可以运行 atest elf_alignment_test,它会验证在搭载 Android 15 及更高版本的设备上设备端 ELF 文件的对齐情况。