Размер страницы – это гранулярность, с которой ОС управляет памятью. Большинство современных процессоров поддерживают страницы размером 4 КБ, поэтому ОС Android и приложения для нее традиционно создавались и оптимизировались для работы с таким размером страниц. Процессоры ARM поддерживают страницы размером 16 КБ, а начиная с Android 15, AOSP также поддерживает сборку Android со страницами размером 16 КБ. Этот вариант использует дополнительную память, но повышает производительность системы. В Android 15 этот параметр не включен по умолчанию, но доступен в режиме разработчика или как параметр для разработчиков приложений и производителей устройств. Это позволяет подготовиться к переходу на режим 16 КБ в будущем.
В Android 15 и более поздних версиях поддерживается сборка Android с выравниванием ELF размером 16 КБ, которое работает с ядрами размером 4 КБ и 16 КБ, начиная с версии android14-6.1.
При использовании с ядром 16 КБ эта конфигурация задействует дополнительную память, но повышает производительность системы.
Как задать размер страницы памяти 16 КБ в Android
Страницы размером 16 КБ поддерживаются только на целевых устройствах arm64 с ядрами 16 КБ.
Однако вы также можете симулировать пространство пользователя 16 КБ на x86_64 для Cuttlefish.
Пространство ядра
Если вы используете Kleaf для сборки ядра, --page_size=16k собирает ядро в режиме 16 КБ.arm64
Если вы напрямую используете конфигурацию ядра Linux, то можете выбрать страницы размером 16 КБ, задав значение CONFIG_ARM64_16K_PAGES вместо CONFIG_ARM64_4K_PAGES.
Информацию о готовых двоичных файлах GKI с размером страницы 16 КБ, поддерживаемых ветвях, выпусках и повторных сборках можно найти в статьях Выпуски GKI с размером страницы 16 КБ и Конечные сборки GKI.
Пользовательское пространство
Чтобы включить поддержку страниц размером 16 КБ в пользовательском пространстве Android, задайте следующие параметры сборки:
PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := trueудаляетPAGE_SIZEdefine и заставляет компоненты определять размер страницы во время выполнения.PRODUCT_MAX_PAGE_SIZE_SUPPORTED := 16384, которая обеспечивает выравнивание файлов ELF платформы по границе 16 КБ. Такой размер выбран для обеспечения совместимости с будущими версиями. При выравнивании ELF по 16 КБ ядро может поддерживать страницы размером 4 КБ и 16 КБ.
Проверьте флаги сборки
Выбрав целевую платформу 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
Если предыдущие две команды вернули значения 16384 и true соответственно, флаги сборки настроены правильно для работы с ядром размером 16 КБ. Однако даже если сборка прошла успешно, во время выполнения могут возникнуть проблемы из-за различий в среде размером 16 КБ.
Программирование системы с размером страницы 16 КБ
Подавляющее большинство кода на любом устройстве Android не имеет прямого отношения к размеру страницы. Однако для кода, который работает со страницами, поведение ядра при выделении памяти меняется. Это нужно учитывать, чтобы писать код, который будет не только совместимым, но и максимально производительным и минимально ресурсоемким.
Если вы вызовете mmap для области размером 1, 2 или 4 КБ в системе с размером страницы 4 КБ, система зарезервирует 4 КБ. Другими словами, при запросе памяти у ядра оно всегда должно округлять запрошенную память до ближайшего размера страницы. Например, если вы выделите область размером 5 КБ в области размером 4 КБ, ядро выделит 8 КБ.
В ядре с размером страницы 16 КБ эти "хвосты" больше. Например, при использовании ядра с размером страницы 16 КБ все эти выделения памяти (от 1 до 5 КБ) будут занимать 16 КБ. Если вы запросите 17 КБ, будет выделено 32 КБ.
Например, в системе с размером страницы 4 КБ можно выделить две анонимные области чтения-записи по 4 КБ. Однако в ядре с размером страницы 16 КБ для этого потребуется выделить две страницы, то есть 32 КБ. Если используется ядро размером 16 КБ, эти регионы можно объединить в одну страницу для чтения или записи, чтобы использовать только 16 КБ. В этом случае будет потрачено впустую 8 КБ по сравнению с ядром размером 4 КБ. Чтобы ещё больше сократить использование памяти, можно объединить больше страниц. На самом деле в максимально оптимизированной системе со страницами размером 16 КБ требуется меньше памяти, чем в системе со страницами размером 4 КБ, поскольку таблица страниц в четыре раза меньше для того же объема памяти.
При использовании mmap округляйте запрашиваемый размер до ближайшего размера страницы. Это гарантирует, что весь объем памяти, выделенный ядром, будет напрямую виден в пользовательском пространстве в виде значений времени выполнения, а не будет запрашиваться неявно и становиться доступным случайно или неявно.
Как создавать общие библиотеки с выравниванием ELF 16 КБ
Чтобы создать общие библиотеки, которые являются частью проекта Android, достаточно настроек, описанных в разделе Как включить размер страницы 16 КБ.
PRODUCT_NO_BIONIC_PAGE_SIZE_MACRO := truePRODUCT_MAX_PAGE_SIZE_SUPPORTED := 16384
Чтобы создать общие библиотеки, которые не входят в проект для Android, вам нужно передать этот флаг компоновщика:
-Wl,-z,max-page-size=16384
Проверьте двоичные файлы и предварительно созданные объекты на соответствие требованиям к выравниванию ELF для страниц размером 16 КБ
Лучший способ проверить выравнивание и поведение во время выполнения – протестировать и запустить приложение на скомпилированном ядре с размером страницы 16 КБ. Однако, чтобы выявлять некоторые проблемы раньше:
Начиная с Android 16, вы можете задать
PRODUCT_CHECK_PREBUILT_MAX_PAGE_SIZE := trueво время сборки. Используйтеignore_max_page_size: trueвAndroid.bpиLOCAL_IGNORE_MAX_PAGE_SIZE := trueвAndroid.mk, чтобы временно игнорировать их. Эти настройки проверяют все предварительно созданные сборки и позволяют обнаружить, когда одна из них обновлена, но не выровнена по 16 КБ.Вы можете запустить
atest elf_alignment_test, чтобы проверить выравнивание ELF-файлов на устройствах с Android 15 и более поздними версиями.