ページサイズとは、OS がメモリを管理する際の粒度です。現在多くの CPU は、4 KB ページサイズをサポートしているため、Android OS やアプリは、4 KB ページサイズを実行できるようにビルド、最適化されてきました。ARM CPU は、より大きな 16 KB ページサイズをサポートしています。また、Android 15 以降、AOSP も 16 KB ページサイズでの Android のビルドをサポートしています。このオプションでは追加のメモリを使用しますが、システム パフォーマンスは向上します。Android 15 では、このオプションはデフォルトでは有効化されていませんが、デベロッパー モードまたはデベロッパー オプションとして利用できます。OEM やアプリ デベロッパーは、将来的にどこでも 16 KB モードに切り替えるための準備ができます。
Android 15 以降では、4 KB および 16 KB カーネルで動作する 16 KB ELF 配置での Android のビルド(android14-6.1
以降)がサポートされます。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_4K_PAGES
の代わりに CONFIG_ARM64_16K_PAGES
を設定することで 16 KB ページを選択できます。
Android ユーザー空間で 16 KB ページサイズのサポートを有効化するには、次のビルド オプションを設定します。
PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := true
:PAGE_SIZE
定義を削除し、実行時にコンポーネントがページサイズを決定するようにします。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
前の 2 つのコマンドで 16384
および true
がそれぞれ返された場合は、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 カーネルの場合、ページのこの余分の「テールエンド」が大きくなります。たとえば、16 KB カーネルで使用される場合で、これらの割り当てのすべて(1 KB から 5 KB まで)を使用する場合、16 KB が割り当てられます。17 KB をリクエストすると、32 KB が割り当てられます。
たとえば、4 KB のシステムで、2 つの 4 KB 読み取り - 書き込み匿名リージョンを割り当てることは問題ありません。ただ、16 KB カーネルでこれを行うと、2 つのページ(32 KB)を割り当てることになります。16 KB カーネルでは、可能である場合にこれらのリージョンを単一の読み取りまたは書き込み可能なページに結合することができ、16 KB のみが使用されるようにすることができますが、4 KB カーネルの場合と比較して 8 KB が無駄になります。メモリ使用量をさらに抑えるには、ページをさらに結合します。実際、最大限に最適化された 16 KB システムでは、16 KB ページで要求されるメモリ量が 4 KB システムよりも少なく、これは、同じメモリに対するページテーブルのサイズが 1/4 になっているためです。
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 アライメントではない更新済みのビルドを検出できます。Android 15 以降でリリースされるデバイスでは、
atest elf_alignment_test
を実行してデバイス上の ELF ファイルのアライメントを確認できます。