W przeszłości Android obsługiwał tylko strony pamięci o rozmiarze 4 KB, co optymalizowało wydajność pamięci systemowej pod kątem średniej ilości pamięci całkowitej, jaką zwykle miały urządzenia z Androidem. Od Androida 15 AOSP obsługuje urządzenia skonfigurowane do używania rozmiaru strony 16 KB (urządzenia 16 KB). Jeśli Twoja aplikacja używa bibliotek NDK bezpośrednio lub pośrednio za pomocą pakietu SDK, musisz ją przebudować, aby działała na urządzeniach o rozmiarze strony 16 KB.
Producenci urządzeń nadal tworzą urządzenia z większą ilością pamięci fizycznej (RAM). Wiele z nich będzie korzystać ze stron o rozmiarze 16 KB (a w przyszłości większych), aby zoptymalizować wydajność urządzenia. Dodanie obsługi urządzeń ze stronami o rozmiarze 16 KB umożliwia uruchamianie aplikacji na tych urządzeniach i korzystanie z powiązanych z tym ulepszeń wydajności. Bez ponownej kompilacji aplikacje nie będą działać na urządzeniach 16 KB w przyszłych wersjach Androida.
Aby pomóc Ci dodać obsługę w aplikacji, przygotowaliśmy wskazówki dotyczące sprawdzania, czy zmiana ma wpływ na Twoją aplikację, ponownego jej kompilowania (w odpowiednich przypadkach) oraz testowania aplikacji w środowisku 16 KB przy użyciu emulatorów (w tym obrazów systemu Android 15 dla emulatora Androida).
Wymagania dotyczące zgodności z Google Play
Aby zapewnić prawidłowe działanie aplikacji w najnowszych wersjach Androida, wszystkie aplikacje kierowane na Androida 15 (API na poziomie 35) i nowsze wersje muszą obsługiwać strony pamięci o rozmiarze 16 KB na 64-bitowych urządzeniach w Google Play. Od 1 lutego 2027 r. nie będziesz mieć możliwości publikowania aktualizacji aplikacji, które nie obsługują stron pamięci o rozmiarze 16 KB.
Korzyści i wzrost wydajności
Urządzenia skonfigurowane z użyciem stron o rozmiarze 16 KB zużywają średnio nieco więcej pamięci, ale zyskują też różne ulepszenia wydajności zarówno systemu, jak i aplikacji:
- Krótszy czas uruchamiania aplikacji, gdy system jest pod presją pamięci: średnio o 3,16% krótszy, a w przypadku niektórych testowanych aplikacji o znacznie więcej (do 30%).
- Zmniejszone zużycie energii podczas uruchamiania aplikacji: średnio o 4,56%
- Szybsze uruchamianie aparatu: średnio o 4,48% szybsze uruchomienia z pamięci i o 6,60% szybsze uruchomienia „na zimno”
- Skrócony czas uruchamiania systemu: skrócenie o 8% (około 950 milisekund)
Te ulepszenia bazują na naszych wstępnych testach. Wyniki na rzeczywistych urządzeniach mogą się różnić. W miarę kontynuowania testów będziemy przeprowadzać dodatkową analizę potencjalnych zysków w przypadku aplikacji.
Sprawdzanie, czy ta zmiana wpłynie na Twoją aplikację
Jeśli Twoja aplikacja używa kodu natywnego, zrekompiluj ją, aby obsługiwała urządzenia 16-kilobajtowe. Jeśli nie masz pewności, czy Twoja aplikacja używa kodu natywnego, możesz za pomocą narzędzia APK Analyzer sprawdzić, czy zawiera ona kod natywny, a następnie sprawdzić wyrównanie segmentów ELF w przypadku znalezionych bibliotek współdzielonych. Android Studio udostępnia też funkcje, które pomagają automatycznie wykrywać problemy z wyrównaniem.
Jeśli Twoja aplikacja używa tylko kodu napisanego w języku programowania Java lub Kotlin, w tym wszystkich bibliotek i pakietów SDK, to już obsługuje urządzenia 16-bitowe. Zalecamy jednak przetestowanie aplikacji w środowisku 16 KB, aby sprawdzić, czy nie występują nieoczekiwane regresje w jej działaniu.
Czy Twoja aplikacja używa kodu natywnego?
Aplikacja używa kodu natywnego, jeśli:
- Twoja aplikacja używa kodu C/C++ (natywnego). Jeśli Twoja aplikacja korzysta z Androida NDK, używa kodu natywnego.
- Twoja aplikacja jest połączona z zewnętrznymi bibliotekami natywnymi lub zależnościami (np. pakietami SDK), które ich używają.
- Twoja aplikacja została utworzona za pomocą kreatora aplikacji innej firmy, który używa bibliotek natywnych na urządzeniu.
Identyfikowanie bibliotek natywnych za pomocą narzędzia APK Analyzer
APK Analyzer to narzędzie, które umożliwia ocenę różnych aspektów skompilowanego pliku APK. Aby sprawdzić, czy aplikacja używa kodu natywnego (niezależnie od tego, czy jest zgodna z trybem 16 KB):
- Otwórz Android Studio, a następnie kliknij Plik > Otwórz i wybierz dowolny projekt.
Na pasku menu kliknij Build > Analyze APK… (Kompiluj > Analizuj plik APK…).
Wybierz plik APK, który chcesz przeanalizować.
Sprawdź folder
lib, w którym znajdują się pliki udostępnionych obiektów (.so), jeśli takie istnieją. Jeśli są obecne udostępnione pliki obiektowe, aplikacja używa kodu natywnego. W kolumnie Wyrównanie wyświetlają się ostrzeżenia dotyczące plików, w których występują problemy z wyrównaniem. Jeśli nie ma żadnych udostępnionych plików obiektów ani folderulib, aplikacja nie używa kodu natywnego.
Wykrywanie problemów z wyrównaniem za pomocą automatycznych kontroli
Android Studio wyświetla ostrzeżenie, jeśli wstępnie skompilowane biblioteki lub pliki APK nie są zgodne z limitem 16 KB. Użyj narzędzia APK Analyzer, aby sprawdzić, które biblioteki wymagają aktualizacji lub czy konieczne są zmiany w kodzie.
Lint w Android Studio wyróżnia też biblioteki natywne, które nie są zgodne z trybem 16 KB.
Sprawdzanie wyrównania segmentów ELF w przypadku bibliotek udostępnionych
W przypadku wszystkich bibliotek wspólnych sprawdź, czy segmenty ELF bibliotek wspólnych są prawidłowo wyrównane przy użyciu wyrównania ELF 16 KB. Jeśli tworzysz aplikacje na Linuksie lub macOS, możesz użyć skryptu check_elf_alignment.sh, jak opisano w następnej sekcji. Możesz też używać narzędzi wiersza poleceń bezpośrednio.
Użyj skryptu check_elf_alignment.sh (Linux lub macOS)
Aby sprawdzić wyrównanie segmentów ELF za pomocą skryptu check_elf_alignment.sh, wykonaj te czynności:
Zapisz skrypt
check_elf_alignment.shw pliku.Uruchom skrypt w pliku APK aplikacji:
check_elf_alignment.sh APK_NAME.apkSkrypt zwraca wartość
ALIGNEDlubUNALIGNEDdla wszystkicharm64-v8azasobów wspólnych.Jeśli jakieś biblioteki współdzielone
arm64-v8alubx86_64sąUNALIGNED, musisz zaktualizować ich pakiety, a następnie ponownie skompilować aplikację i przetestować ją, wykonując czynności opisane w tej sekcji.
Bezpośrednie używanie narzędzi wiersza poleceń
Aby sprawdzić wyrównanie segmentów ELF bezpośrednio za pomocą narzędzi wiersza poleceń, wykonaj te czynności:
- Upewnij się, że narzędzia Android SDK Build-Tools w wersji 35.0.0 lub nowszej oraz Android NDK są zainstalowane za pomocą SDK Managera w Android Studio lub narzędzia wiersza poleceń
sdkmanager. Wyodrębnij plik APK aplikacji:
Linux lub macOS
unzip APK_NAME.apk -d /tmp/my_apk_outWindows (PowerShell)
Expand-Archive -Path .\APK_NAME.apk -DestinationPath ~\tmp\my_apk_outW tymczasowym katalogu, do którego został wyodrębniony plik APK, sprawdź zawartość katalogu
libpod kątem plików obiektów współdzielonych (.so). Są to te same pliki obiektów współdzielonych, które można zobaczyć podczas identyfikowania bibliotek natywnych za pomocą narzędzia APK Analyzer. Uruchom to polecenie w przypadku każdego pliku obiektu udostępnionego:Linux lub macOS
SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-objdump -p SHARED_OBJECT_FILE.so | grep LOADWindows (PowerShell)
SDK_ROOT_LOCATION\Android\sdk\ndk\NDK_VERSION\toolchains\llvm\prebuilt\windows-x86_64\bin\llvm-objdump.exe -p SHARED_OBJECT_FILE.so | Select-String -Pattern "LOAD"Gdzie
SDK_ROOT_LOCATIONto ścieżka do katalogu, w którym zainstalowano pakiet Android SDK,SHARED_OBJECT_FILEto nazwa sprawdzanego pliku obiektu udostępnionego, aNDK_VERSIONto zainstalowana wersja pakietu Android NDK (np.28.0.12433566). W przypadku każdego sprawdzanego pliku dane wyjściowe będą wyglądać mniej więcej tak:LOAD off 0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**14 LOAD off 0x0000000000042a90 vaddr 0x0000000000043a90 paddr 0x0000000000043a90 align 2**14 LOAD off 0x0000000000046230 vaddr 0x0000000000048230 paddr 0x0000000000048230 align 2**14Sprawdź linie wyjściowe, aby upewnić się, że segmenty obciążenia nie mają wartości mniejszych niż
2**14. Jeśli którykolwiek z segmentów ładowania ma wartość2**13,2**12lub niższą, musisz zaktualizować pakiet tych bibliotek, a następnie ponownie skompilować aplikację i przeprowadzić test zgodnie z instrukcjami w tej sekcji.Następnie uruchom narzędzie wiersza poleceń
zipalignna pliku APK aplikacji:Linux lub macOS
SDK_ROOT_LOCATION/Android/sdk/build-tools/35.0.0/zipalign -v -c -P 16 4 APK_NAME.apkWindows (PowerShell)
SDK_ROOT_LOCATION\Android\sdk\build-tools\35.0.0\zipalign.exe -v -c -P 16 4 APK_NAME.apkGdzie
SDK_ROOT_LOCATIONto ścieżka do katalogu, w którym zainstalowano pakiet Android SDK, aAPK_NAMEto nazwa pliku APK aplikacji. Jeśli wszystkie biblioteki współdzielone są prawidłowo dopasowane, w ostatnim wierszu danych wyjściowych pojawi się komunikat „Verification successful” (Weryfikacja zakończona).Jeśli weryfikacja się nie powiodła, niektóre biblioteki współdzielone wymagają ponownego wyrównania, więc musisz zaktualizować pakiet tych bibliotek, a następnie ponownie skompilować aplikację i ponownie przetestować ją, wykonując czynności opisane w tej sekcji.
Sprawdzanie flagi zabezpieczeń RELRO
Aby ograniczyć luki w zabezpieczeniach, nowoczesne linkery używają flagi Relocation Read-Only (RELRO), aby po wczytaniu sekcje relokacji udostępnionego pliku obiektowego były tylko do odczytu. Włącz flagę RELRO w kompilacji.
Sekcja RELRO, której adres początkowy i rozmiar segmentu (MemSize) nie są wyrównane do 16 KB, powoduje awarię aplikacji w czasie działania z błędem segmentacji. Dzieje się tak, jeśli plik .so został utworzony za pomocą zestawu narzędzi NDK w wersji 27 lub starszej bez włączania odpowiednich flag.
Uruchom to polecenie w przypadku każdego pliku obiektu współdzielonego (Linux lub macOS):
SDK_ROOT_LOCATION/Android/sdk/ndk/NDK_VERSION/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-readelf -Wl SHARED_OBJECT_FILE.so | grep 'RELRO\|Type'
Ciąg znaków GNU_RELRO jest drukowany, jeśli istnieje segment RELRO.
Następnie sprawdź dopasowanie segmentu RELRO, sumując jego wirtualny adres przesunięcia (VirtAddr) z rozmiarem pamięci segmentu (MemSiz) i dzieląc wynik przez 16 KB (0x4000). Jeśli reszta (modulo) wynosi 0, segment RELRO jest wyrównany do 16 KB.
Oto przykład pliku .so, który nie jest dopasowany:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x01510 R 0x1
Wzór: (VirtAddr + MemSiz) % 0x4000 == 0
Wynik: (0xdfaf0 + 0x01510) % 0x4000 = 0xE1000 % 0x4000 == 0x1000
Ponieważ 0x1000 nie jest równe 0, ten plik .so nie jest zgodny z trybem 16 KB. Zakres ochrony RELRO od DC000 (poprzedni podział strony) do E4000 jest tylko do odczytu, ale linker Androida oczekuje, że podzakres od E1000 do E4000 będzie zapisywalny, co powoduje błąd segmentacji. W takim przypadku ponownie skompiluj plik .so zgodnie z opisem w sekcji Kompilowanie aplikacji z wyrównaniem ELF do 16 KB.
Oto przykład wyrównanego pliku .so z segmentem RELRO:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x00510 R 0x1
Oto przykład pliku .so bez segmentu RELRO:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
Jest to plik .so, który jest zgodny z trybem 16 KB i nie zawiera segmentu RELRO.
Oto przykład wyrównanego pliku .so, w którym GNU_RELRO znajduje się we własnym segmencie LOAD:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x000680 0x000680 R E 0x4000
LOAD 0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x000980 RW 0x4000
GNU_RELRO 0x000680 0x0000000000004680 0x0000000000004680 0x0001d8 0x000980 R 0x1
Wzór: (VirtAddr + MemSiz) % 0x4000 == 0
Wynik: (0x4680 + 0x0980) % 0x4000 = 0x5000 % 0x4000 == 0x1000
Chociaż 0x1000 nie jest zerem, ten plik .so jest zgodny z trybem 16 KB.
Formuła modulo ma zastosowanie, gdy GNU_RELRO udostępnia segment LOAD kolejnym danym do zapisu (takim jak .data lub .bss).
Aby sprawdzić, czy GNU_RELRO znajduje się we własnym segmencie LOAD, sprawdź nagłówki programu, uruchamiając llvm-readelf -Wl i filtrując za pomocą grep 'LOAD\|RELRO\|Type'. Porównaj VirtAddr i MemSiz w przypadku GNU_RELRO z zawierającym je segmentem LOAD. W tym przykładzie oba mają VirtAddr 0x4680 i MemSiz 0x0980.
Ponieważ cały segment LOAD zawiera tylko dane RELRO, w podzakresie od 0x5000 do 0x8000 nie ma danych, które można by zapisać. Dodatkowo każdy kolejny segment LOAD z możliwością zapisu zaczyna się na osobnej stronie o rozmiarze 16 KB (od adresu 0x8000 lub wyższego). Ochrona tylko do odczytu linkera nie będzie się nakładać na żadne dane, które można zapisywać, więc nie wystąpi błąd segmentacji.
Tworzenie aplikacji z obsługą urządzeń ze stronami pamięci 16 KB
Jeśli aplikacja używa kodu natywnego, wykonaj czynności opisane w poniższych sekcjach, aby upewnić się, że obsługuje ona urządzenia z rozmiarem strony 16 KB:
- Aktualizowanie pakietów bibliotek udostępnionych
- Kompilowanie aplikacji z użyciem wyrównania ELF 16 KB
- Poprawianie kodu i rozwiązywanie problemów ze środowiskiem wykonawczym
- Optymalizacja niestandardowych alokatorów pamięci (jeśli dotyczy)
- Sprawdzanie, czy pakiety SDK obsługują strony pamięci o rozmiarze 16 KB
Aktualizowanie pakietów bibliotek udostępnionych
Przejdź na wtyczkę Androida do obsługi Gradle w wersji 8.5.1 lub nowszej i używaj nieskompresowanych bibliotek współdzielonych.
Użyj bundletool, aby sprawdzić wyrównanie zamka błyskawicznego
Aby sprawdzić wyrównanie pakietu, użyj:
bundletool dump config --bundle=<my .aab> | grep alignment
Jeśli widzisz PAGE_ALIGNMENT_16K, oznacza to, że pakiet wymaga wyrównania do 16 KB. Jeśli widzisz PAGE_ALIGNMENT_4K, oznacza to, że pliki .so w pliku ZIP w pliku APK utworzonym z tego pakietu AAB są wyrównane do 4 KB.
Wtyczka Androida do obsługi Gradle w wersji 8.5.1 lub nowszej
Urządzenia 16 KB wymagają, aby aplikacje dostarczane z nieskompresowanymi bibliotekami współdzielonymi były wyrównane do granicy 16 KB. Aby to zrobić, musisz uaktualnić wtyczkę Androida do obsługi Gradle (AGP) do wersji 8.5.1 lub nowszej. Szczegółowe informacje o procesie uaktualniania znajdziesz w sekcji Asystent uaktualniania wtyczki Android do Gradle.
AGP w wersji 8.5 lub starszej
Jeśli nie możesz uaktualnić AGP do wersji 8.5.1 lub nowszej, możesz zamiast tego przejść na skompresowane biblioteki udostępnione. Zaktualizuj konfigurację Gradle, aby Gradle kompresował biblioteki udostępnione podczas pakowania aplikacji. Pozwoli to uniknąć problemów z instalacją aplikacji z bibliotekami udostępnionymi, które nie są zgodne z trybem 16 KB.
Dynamiczny
W pliku build.gradle dodaj tę opcję:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
Kotlin
W pliku build.gradle.kts dodaj tę opcję:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
AGP w wersji 8.0 lub starszej,
Jeśli używasz AGP w wersji 8.0 lub starszej, musisz też wyłączyć opcję nieskompresowanej biblioteki natywnej w przypadku pakietów aplikacji w pliku gradle.properties:
android.bundle.enableUncompressedNativeLibs=false
Skompiluj aplikację z uwzględnieniem wyrównania ELF do 16 KB
Urządzenia z 16 KB wymagają, aby segmenty ELF zasobów wspólnych były prawidłowo wyrównane przy użyciu wyrównania ELF 16 KB, aby aplikacja mogła działać.
Jeśli jesteś deweloperem gier i Twoja gra działa na silniku gry Unity, zapoznaj się z przewodnikiem po Unity. Jeśli Twoja gra działa na silniku Unreal, zapoznaj się z przewodnikiem po Unreal.Jeśli używasz natywnego silnika gry, kontynuuj czytanie tego przewodnika.
Aby skompilować aplikację pod kątem obsługi stron 16 KB przez pliki ELF, wykonaj czynności opisane w jednej z poniższych sekcji, w zależności od używanej wersji Android NDK.
Android NDK r28 lub nowszy,
Wersje NDK r28 i nowsze domyślnie kompilują kod z wyrównaniem do stron 16 KB.
Android NDK w wersji r27 lub starszej
Aby obsługiwać kompilowanie bibliotek współdzielonych dostosowanych do stron 16 KB za pomocą Android NDK w wersji r27 lub starszej, użyj tych flag linkera:
-Wl,-z,max-page-size=16384
-Wl,-z,common-page-size=16384
Aby zaktualizować pliki konfiguracyjne systemu kompilacji:
ndk-build
Jeśli używasz ndk-build, zaktualizuj Android.mk, aby włączyć wyrównanie ELF o rozmiarze 16 KB:
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
CMake
Jeśli używasz CMake, zaktualizuj CMakeLists.txt, aby włączyć wyrównanie ELF o rozmiarze 16 KB:
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-Wl,-z,max-page-size=16384"
"-Wl,-z,common-page-size=16384"
)
Poprawianie kodu i rozwiązywanie problemów z czasem działania
Nawet jeśli aplikacja jest dostosowana do 16 KB, mogą w niej występować błędy, jeśli w kodzie znajdują się miejsca, w których zakłada się, że urządzenie używa określonego rozmiaru strony. Aby tego uniknąć, wykonaj te czynności:
Usuń wszystkie zakodowane na stałe zależności, które odwołują się do stałej
PAGE_SIZE, lub instancje w logice kodu, które zakładają, że rozmiar strony urządzenia wynosi 4 KB (4096).Zamiast niej użyj zasady
getpagesize()lubsysconf(_SC_PAGESIZE).Poszukaj użycia funkcji
mmap()i innych interfejsów API, które wymagają argumentów wyrównanych do strony, i w razie potrzeby zastąp je alternatywnymi rozwiązaniami.
W niektórych przypadkach, jeśli aplikacja używa wartości PAGE_SIZE jako wygodnej wartości, która nie jest powiązana z rozmiarem strony, nie spowoduje to awarii aplikacji w trybie 16 KB. Jeśli jednak ta wartość zostanie przekazana do jądra za pomocą mmap bez MAP_FIXED, jądro nadal będzie używać całej strony, co spowoduje marnowanie pamięci. Z tych powodów wartość PAGE_SIZE jest nieokreślona, gdy w NDK w wersji 27 lub nowszej włączony jest tryb 16 KB.
Jeśli Twoja aplikacja używa PAGE_SIZE w ten sposób i nigdy nie przekazuje tej wartości bezpośrednio do jądra, zamiast PAGE_SIZE utwórz nową zmienną o nowej nazwie, aby odzwierciedlić, że jest ona używana do innych celów i nie odzwierciedla rzeczywistej strony pamięci.
Optymalizacja niestandardowych alokatorów pamięci
W systemach 16 KB najmniejsza jednostka pamięci fizycznej przydzielana przez system operacyjny jest 4 razy większa niż w systemach 4 KB. Jeśli niestandardowy alokator został zaprojektowany z uwzględnieniem założeń dotyczących 4 KB, może rozpraszać małe obiekty na wielu stronach 16 KB i niepotrzebnie zachowywać pustą pamięć. Może to znacznie zwiększyć wykorzystanie pamięci fizycznej (RSS) i obniżyć wydajność skompresowanej przestrzeni wymiany (ZRAM).
Jeśli Twój kod zarządza własnymi pulami pamięci, postępuj zgodnie z tymi zaleceniami:
1. Unikaj zakodowanych na stałe progów bajtów zwalniania pamięci
Wielu alokatorów używa stałych limitów bajtów, aby decydować, kiedy zwolnić pamięć z powrotem do systemu operacyjnego za pomocą madvise(MADV_DONTNEED) (np. zwalniaj pamięć tylko wtedy, gdy aktywne obiekty zajmują mniej niż 8 KB).
W systemie 16 KB nawet pojedynczy aktywny obiekt o rozmiarze 16 bajtów przypina całą stronę 16 KB (czyli większą niż 8 KB). W rezultacie próg zwolnienia nigdy nie zostaje osiągnięty, a alokator nigdy nie zwraca do jądra otaczającej go nieużywanej pamięci.
Co zrobić: nigdy nie używaj stałych wartości bajtów zakodowanych na stałe w heurystykach dotyczących publikowania stron.
Dynamicznie skaluj progi zwalniania w czasie działania na podstawie rzeczywistego rozmiaru strony za pomocą sysconf(_SC_PAGESIZE).
2. Najpierw wypełniaj już używane strony (alokacja „najpierw gęsto”).
Jeśli alokator przydziela pamięć w kolejności FIFO (pierwszy na wejściu, pierwszy na wyjściu) lub cyklicznej, nowe alokacje są rozproszone na wielu częściowo wypełnionych stronach o rozmiarze 16 KB. Pojedynczy obiekt na stronie zajmuje 16 KB w fizycznej pamięci RAM.
Co zrobić: zawsze przydzielaj nowe obiekty ze strony lub płyty, która jest najbardziej zapełniona (najgęstsza), zanim zaczniesz używać pustych lub rzadko używanych stron. Skupienie nowych przydziałów na już zapełnionych stronach pozwala na naturalne opróżnienie rzadko używanych stron do zera aktywnych obiektów, dzięki czemu cała strona o rozmiarze 16 KB może zostać zwolniona i przekazana systemowi operacyjnemu.
3. Wyrównaj pule pamięci do 16 KB i utrzymuj ich rozmiary na umiarkowanym poziomie.
Zakresy obejmujące wiele stron, które są przeznaczone dla systemów 4 KB, mogą zawierać nadmierny, niezwolniony nadmiar pamięci w jądrach 16 KB. Dodatkowo klasy rozmiaru, które nie dzielą się równomiernie na 16 KB, powodują fragmentację na końcu każdej strony.
Co zrobić:
- Upewnij się, że wszystkie pule pamięci, granice bloków i wyrównania buforów są dokładnymi wielokrotnościami rozmiaru strony środowiska wykonawczego.
- Ponownie oceń rozmiary zakresów wielostronicowych dla klas małych obiektów, aby uniknąć przydzielania zbyt dużych bloków, które blokują nieużywaną pamięć.
4. Natychmiastowe zwalnianie pamięci fizycznej na potrzeby dużych buforów w pamięci podręcznej
Niestandardowe alokatory często buforują duże bufory (> 64 KB) w pamięci, aby można było ich ponownie używać bez narzutu związanego z wywołaniami systemowymi mmap lub munmap. Jednak przechowywanie tych nieaktualnych buforów w pamięci marnuje megabajty fizycznej pamięci RAM podczas oczekiwania na licznik czasu wykluczenia.
Co zrobić: zachowaj zakres adresów pamięci wirtualnej zarezerwowany do szybkiego ponownego użycia, ale podczas zwracania bufora do pamięci podręcznej natychmiast wywołaj madvise(..., MADV_DONTNEED) lub madvise(..., MADV_FREE). System operacyjny od razu odzyskuje fizyczną pamięć RAM, a aplikacja może natychmiast ponownie użyć adresu wirtualnego bez ponownego przydzielania.
5. Zerowanie pamięci podczas zwalniania, a nie podczas przydzielania na potrzeby kompresji ZRAM
Android używa skompresowanej przestrzeni wymiany (ZRAM), aby przechowywać aplikacje działające w tle w pamięci. Na urządzeniach z rozmiarem strony 16 KB, jeśli strona zawiera choćby 1 aktywny obiekt, cała strona 16 KB pozostaje w pamięci lub jest przenoszona do ZRAM. Pozostałe niepotrzebne dane (takie jak nieaktualne wskaźniki i ciągi znaków) w uprzednio zwolnionych częściach tej strony słabo się kompresują.
Jeśli alokator zeruje pamięć (np. ze względów bezpieczeństwa lub w przypadku alokacji zainicjowanych zerem), rozważ zerowanie podczas zwalniania pamięci (free()), a nie podczas alokacji:
- Przypięte strony kosztują mniej: nieużywana pamięć na częściowo wypełnionych stronach o rozmiarze 16 KB jest kompresowana w ZRAM do niemal zerowego rozmiaru, więc przypięte strony nie marnują fizycznej przestrzeni wymiany.
- Minimalne obciążenie pamięci podręcznej: w momencie wywołania funkcji
free()pamięć jest już aktywna w pamięci podręcznej procesora, co pozwala uniknąć późniejszych braków danych w pamięci podręcznej.
Podsumowanie rekomendacji
| Obszar | Rekomendacja | Oczekiwany wpływ |
|---|---|---|
| Progi usuwania | Dynamicznie skaluj progi publikacji za pomocą sysconf(_SC_PAGESIZE). |
Zapobiega trwałemu blokowaniu logiki wersji. |
| Zamówienie alokacji | Przydziel najpierw z najgęstszej (prawie pełnej) strony lub płyty. | Zmniejsza pamięć rezydentną (RSS) przez pakowanie aktywnych obiektów. |
| Rozmiar zakresu | Dopasuj klasy rozmiarów do wielokrotności 16 KB i unikaj zbyt dużych bloków. | Eliminuje fragmentację stron końcowych i zmniejsza marnowanie pamięci. |
| Pamięci podręczne buforów | Podczas buforowania dużych buforów natychmiast wywołaj madvise(MADV_DONTNEED). |
Eliminuje nieużywaną pamięć RAM, zachowując szybkie wirtualne ponowne użycie. |
| Swap / ZRAM | Zeruj pamięć w free(), a nie podczas alokacji. |
Poprawia współczynniki kompresji ZRAM, dzięki czemu przypięte strony kosztują mniej. |
Sprawdzanie, czy pakiety SDK obsługują strony pamięci o rozmiarze 16 KB
Wiele pakietów SDK jest zgodnych ze stronami o rozmiarze 16 KB, zwłaszcza jeśli tworzysz je samodzielnie lub korzystasz z najnowszych gotowych wersji. Niektóre gotowe pakiety SDK lub wersje pakietów SDK nie są jednak zgodne z rozmiarem 16 KB, dlatego sprawdź na stronie każdego dostawcy pakietu SDK, której wersji należy używać z rozmiarem 16 KB.
Przetestuj aplikację w środowisku 16 KB
Po utworzeniu aplikacji z obsługą urządzeń ze stronami pamięci 16 KB warto przetestować ją w środowisku 16 KB, aby sprawdzić, czy nie występują w niej żadne regresje. W tym celu wykonaj następujące czynności:
Skonfiguruj pakiet SDK Androida 15 lub nowszego.
Skonfiguruj jedno z tych środowisk testowych:
- Konfigurowanie narzędzia Android Emulator za pomocą obrazu systemu Android 15 opartego na stronach 16 KB
- Korzystanie z Cuttlefish ze stronami o rozmiarze 16 KB na urządzeniach z architekturą ARM64
- Symulowanie Cuttlefish ze stroną o rozmiarze 16 KB na x86-64
- Włączanie trybu 16 KB na urządzeniu za pomocą opcji programisty
- Korzystanie z laboratorium testów zdalnych Samsung na urządzeniach obsługujących strony o rozmiarze 16 KB
Uruchom urządzenie testowe, a następnie wykonaj to polecenie, aby sprawdzić, czy używa ono środowiska 16 KB:
adb shell getconf PAGE_SIZEPolecenie powinno zwrócić wartość
16384.Aby sprawdzić, czy aplikacja jest wyrównana do 16 KB, uruchom to polecenie
zipalign, gdzie APK_NAME to nazwa pliku APK aplikacji:zipalign -c -P 16 -v 4 APK_NAME.apkDokładnie przetestuj aplikację, zwracając szczególną uwagę na obszary, na które może mieć wpływ zmiana instancji kodu odwołujących się do określonych rozmiarów stron.
Konfigurowanie narzędzia Android Emulator za pomocą obrazu systemu o rozmiarze 16 KB
Aby skonfigurować środowisko 16 KB za pomocą emulatora Androida, wykonaj te czynności:
- W Android Studio kliknij Narzędzia > Menedżer SDK.
Na karcie Platformy pakietu SDK kliknij Pokaż szczegóły pakietu, a następnie rozwiń sekcję Android VanillaIceCream lub nowszą i wybierz 1 lub oba te obrazy systemu emulatora w zależności od tego, jakie urządzenia wirtualne chcesz utworzyć:
- Obraz systemu interfejsów API Google Experimental 16 KB Page Size ARM 64 v8a
- Obraz systemu interfejsy API Google Experimental 16 KB Page Size Intel x86_64 Atom System Image
Kliknij Apply > OK (Zastosuj > OK), aby pobrać wybrane obrazy systemu.
Wykonaj czynności opisane w artykule konfigurowanie urządzenia wirtualnego z Androidem 15. Gdy pojawi się prośba o wybranie obrazu systemu, wybierz pobrany obraz systemu 16 KB. Jeśli nie jest on zalecany automatycznie, obraz systemu 16 KB znajdziesz na karcie Inne obrazy.
Uruchom emulator
Po skonfigurowaniu narzędzia Android Emulator i urządzeń wirtualnych uruchom emulator z menu urządzenia docelowego lub z wiersza poleceń.
Włączanie trybu 16 KB na urządzeniu za pomocą opcji programisty
Włącz opcję programisty Uruchom ze stroną 16 KB, aby uruchomić urządzenie w trybie 16 KB.
W wersjach QPR Androida 15 możesz skorzystać z opcji dla programistów dostępnej na niektórych urządzeniach, aby uruchomić urządzenie w trybie 16 KB i przeprowadzić testowanie na urządzeniu. Zanim skorzystasz z opcji programisty, otwórz Ustawienia > System > Aktualizacje oprogramowania i zastosuj wszystkie dostępne aktualizacje.
Ta opcja dla programistów jest dostępna na tych urządzeniach:
Pixel 8 i 8 Pro (z Androidem 15 QPR1 lub nowszym)
Pixel 8a (z Androidem 15 QPR1 lub nowszym)
Pixel 9, 9 Pro i 9 Pro XL (z Androidem 15 QPR2 lub nowszym)
Pixel 9a (z Androidem 16 lub nowszym)
Tryb zgodności z 16 KB
Ostrzeżenie w trybie zgodności z rozmiarem strony
Opcja zgodności wstecznej 16 KB jest dostępna, gdy urządzenie działa z jądrem 16 KB. Menedżer pakietów uruchamia aplikację w trybie zgodności wstecznej 16 KB, gdy spełnione są te warunki:
- Jeśli aplikacja zawiera pliki ELF (z rozszerzeniem
.so) z wyrównaniem segmentu LOAD o rozmiarze 4 KB. - Jeśli spakowany plik APK zawiera nieskompresowane pliki ELF o rozmiarze 4 KB wyrównane do ZIP.
Jeśli menedżer pakietów włączył tryb zgodności wstecznej 16 KB dla aplikacji, przy pierwszym uruchomieniu aplikacja wyświetli ostrzeżenie, że działa w trybie zgodności wstecznej 16 KB.
Tryb zgodności wstecznej z rozmiarem strony 16 KB umożliwia działanie niektórych aplikacji, ale aby zapewnić najlepszą niezawodność i stabilność, aplikacje powinny być dostosowane do rozmiaru strony 16 KB.
Na stronie z informacjami o aplikacji w sekcji Zaawansowane włącz lub wyłącz ustawienie Uruchamiaj aplikację w trybie zgodności z rozmiarem strony, aby włączyć lub wyłączyć tryb zgodności wstecznej 16 KB w przypadku konkretnej aplikacji. To ustawienie jest widoczne tylko wtedy, gdy urządzenie działa ze stronami o rozmiarze 16 KB.
Ustawienie trybu zgodności z rozmiarem strony
Aby wymusić zgodność wsteczną z rozmiarem 16 KB w przypadku każdej aplikacji na urządzeniu:
adb shell setprop bionic.linker.16kb.app_compat.enabled true
adb shell setprop pm.16kb.app_compat.disabled false
Aby wymusić wyłączenie zgodności wstecznej z rozmiarem 16 KB w przypadku wszystkich aplikacji na urządzeniu:
adb shell setprop bionic.linker.16kb.app_compat.enabled false
adb shell setprop pm.16kb.app_compat.disabled true
W Androidzie 17 możesz też wymusić wyłączenie zgodności wstecznej z 16 KB w przypadku każdej aplikacji i spowodować natychmiastowe przerwanie działania każdego niekompatybilnego pliku binarnego:
adb shell setprop bionic.linker.16kb.app_compat.enabled fatal
adb shell setprop pm.16kb.app_compat.disabled true
Ustaw właściwość android:pageSizeCompat na wartość enabled lub disabled, aby włączyć lub wyłączyć tryb zgodności wstecznej dla konkretnej aplikacji w jej pliku AndroidManifest.xml. Gdy ta właściwość jest ustawiona, aplikacja nie wyświetla ostrzeżeń o trybie zgodności wstecznej podczas uruchamiania.