از لحاظ تاریخی، اندروید تنها از اندازه صفحات حافظه 4 کیلوبایتی پشتیبانی میکند که عملکرد حافظه سیستم را برای میانگین کل حافظهای که دستگاههای اندرویدی معمولا دارند بهینه میکند. با شروع Android 15، AOSP از دستگاه هایی پشتیبانی می کند که برای استفاده از اندازه صفحه 16 کیلوبایت (دستگاه های 16 کیلوبایت) پیکربندی شده اند. اگر برنامه شما از کتابخانه های NDK استفاده می کند، چه به طور مستقیم یا غیرمستقیم از طریق یک SDK، باید برنامه خود را بازسازی کنید تا بتواند روی این دستگاه های 16 کیلوبایتی کار کند.
از آنجایی که سازندگان دستگاهها به ساخت دستگاههایی با حافظه فیزیکی (RAM) بیشتر ادامه میدهند، بسیاری از این دستگاهها از اندازه صفحه ۱۶ کیلوبایت (و در نهایت بیشتر) برای بهینهسازی عملکرد دستگاه استفاده میکنند. افزودن پشتیبانی برای دستگاههای اندازه صفحه 16 کیلوبایت، برنامه شما را قادر میسازد تا در این دستگاهها اجرا شود و به برنامه شما کمک میکند از بهبودهای عملکرد مرتبط بهره مند شود. بدون کامپایل مجدد، برنامه ها در نسخه های بعدی اندروید روی دستگاه های 16 کیلوبایتی کار نخواهند کرد.
برای کمک به اضافه کردن پشتیبانی از برنامه خود، راهنمایی هایی در مورد نحوه بررسی اینکه آیا برنامه شما تحت تأثیر قرار گرفته است ، نحوه بازسازی برنامه خود (در صورت وجود) و نحوه آزمایش برنامه خود در یک محیط 16 کیلوبایتی با استفاده از شبیه سازها (از جمله تصاویر سیستم Android 15 برای شبیه ساز Android) را ارائه کرده ایم.
الزام سازگاری با Google Play
برای اطمینان از اینکه برنامهتان بهدرستی با جدیدترین نسخه Android کار میکند، همه برنامههایی که Android 15 (میانای برنامهسازی کاربردی سطح ۳۵) و بالاتر را هدفیابی میکنند باید از اندازههای صفحه حافظه ۱۶ کیلوبایتی در دستگاههای ۶۴ بیتی در Google Play پشتیبانی کنند. از ۱ فوریه ۲۰۲۷، اگر بهروزرسانیهای برنامهتان از اندازههای صفحه حافظه ۱۶ کیلوبایتی پشتیبانی نکند، نمیتوانید این بهروزرسانیها را منتشر کنید.
مزایا و بهبود عملکرد
دستگاه هایی که با اندازه صفحه 16 کیلوبایت پیکربندی شده اند به طور متوسط کمی از حافظه بیشتری استفاده می کنند، اما بهبودهای عملکردی مختلفی را برای سیستم و برنامه ها نیز به دست می آورند:
- زمانهای راهاندازی برنامه کمتر زمانی که سیستم تحت فشار حافظه است: به طور متوسط 3.16٪ کمتر، با بهبودهای قابل توجه (تا 30٪) برای برخی از برنامههایی که آزمایش کردیم.
- کاهش مصرف انرژی در حین راه اندازی برنامه: به طور متوسط 4.56٪ کاهش
- راهاندازی سریعتر دوربین: به طور متوسط 4.48٪ سریعتر استارتهای گرم و 6.60٪ سریعتر شروع سرد.
- بهبود زمان بوت سیستم: به طور متوسط 8٪ (تقریباً 950 میلی ثانیه) بهبود یافته است.
این پیشرفتها بر اساس آزمایش اولیه ما هستند و نتایج روی دستگاههای واقعی احتمالاً متفاوت خواهد بود. در ادامه آزمایش خود، تجزیه و تحلیل بیشتری از دستاوردهای بالقوه برای برنامه ها ارائه خواهیم کرد.
بررسی کنید آیا برنامهتان تحتتأثیر قرار گرفته است یا نه
اگر برنامه شما از هر کد بومی استفاده می کند ، باید برنامه خود را با پشتیبانی از دستگاه های 16 کیلوبایتی بازسازی کنید . اگر مطمئن نیستید که برنامه شما از کد بومی استفاده میکند، میتوانید از APK Analyzer برای شناسایی وجود کد بومی استفاده کنید و سپس تراز بخشهای ELF را برای کتابخانههای مشترکی که پیدا کردید بررسی کنید . Android Studio همچنین ویژگی هایی را ارائه می دهد که به شما کمک می کند تا به طور خودکار مشکلات تراز را تشخیص دهید .
اگر برنامه شما فقط از کدهای نوشته شده به زبان برنامه نویسی جاوا یا کاتلین استفاده می کند که شامل همه کتابخانه ها یا SDK می شود، برنامه شما از قبل از دستگاه های 16 کیلوبایتی پشتیبانی می کند. با این وجود، توصیه می کنیم برنامه خود را در یک محیط 16 کیلوبایتی آزمایش کنید تا مطمئن شوید که هیچ رگرسیون غیرمنتظره ای در رفتار برنامه وجود ندارد.
آیا برنامه شما از کد بومی استفاده میکند؟
اگر هریک از موارد زیر صدق کند، برنامهتان از کد بومی استفاده میکند:
- برنامه شما از هرگونه کد C/C++ (بومی) استفاده میکند. اگر برنامهتان از Android NDK استفاده میکند، برنامهتان از کد بومی استفاده میکند.
- برنامهتان به کتابخانهها یا وابستگیهای بومی شخص ثالث (مانند کیتهای توسعه نرمافزار) که از آنها استفاده میکنند پیوند دارد.
- برنامه شما را سازنده برنامه طرف سومی ساخته است که از کتابخانههای بومی در دستگاه استفاده میکند.
شناسایی کتابخانههای بومی بااستفاده از «تحلیلکننده APK»
تحلیلکننده APK ابزاری است که به شما امکان میدهد جنبههای مختلف APK ساختهشده را ارزیابی کنید. برای بررسی اینکه برنامه شما از کد بومی استفاده میکند یا نه (صرفنظر از اینکه با اندازه صفحه ۱۶ کیلوبایتی سازگار است یا نه):
- Android Studio را باز کنید، سپس روی File > Open کلیک کنید و پروژهای را انتخاب کنید.
از نوار منو، روی Build > Analyze APK... (ساختن > تجزیهوتحلیل APK…) کلیک کنید
APK موردنظرتان را برای تجزیهوتحلیل انتخاب کنید.
در پوشه
lib، که میزبان فایلهای شیء همرسانیشده (.so) است، جستجو کنید اگر فایلهایی وجود داشته باشد. اگر فایلهای شیء همرسانیشدهای وجود داشته باشد، برنامهتان از کد بومی استفاده میکند. ستون تراز پیامهای هشدار را برای هر فایلی که مشکل تراز دارد نمایش میدهد. اگر هیچ فایل شیء همرسانیشدهای وجود ندارد یا پوشهlibوجود ندارد، برنامهتان از کد بومی استفاده نمیکند.
شناسایی مشکلات همترازی با بررسیهای خودکار
اگر کتابخانهها یا فایلهای APK ازپیشساختهشده شما با ۱۶ کیلوبایت سازگار نباشد، Android Studio پیشدستانه به شما هشدار میدهد. از ابزار تحلیلکننده APK برای بررسی اینکه کدام کتابخانهها باید بهروز شوند یا اینکه آیا تغییرات کد لازم است یا نه استفاده کنید.
Lint در «استودیو Android» نیز کتابخانههای بومی را که با اندازه ۱۶ کیلوبایت تراز نیستند برجسته میکند.
تراز بخشهای ELF را برای کتابخانههای مشترک بررسی کنید
برای هر کتابخانه مشترک، بررسی کنید که بخشهای ELF کتابخانههای مشترک
بااستفاده از تراز ELF ۱۶ کیلوبایتی بهدرستی تراز شده باشند. اگر درحال توسعه در Linux یا macOS هستید، میتوانید از دستورات check_elf_alignment.sh همانطور که در بخش زیر توضیح داده شده است استفاده کنید. همچنین میتوانید مستقیماً از ابزارهای خط فرمان استفاده کنید.
از اسکریپت check_elf_alignment.sh (Linux یا macOS) استفاده کنید
برای بررسی تراز بخشهای ELF بااستفاده از
check_elf_alignment.sh دستورگان، این مراحل را دنبال کنید:
برنامه
check_elf_alignment.shرا در فایلی ذخیره کنید.اجرای دستورگان روی فایل APK برنامه:
check_elf_alignment.sh APK_NAME.apkاین متن برای همه کتابخانههای مشترک
arm64-v8a،ALIGNEDیاUNALIGNEDرا برمیگرداند.اگر هرکدام از کتابخانههای مشترک
arm64-v8aیاx86_64UNALIGNEDهستند، باید بستهبندی آن کتابخانهها را بهروز کنید، سپس برنامهتان را بازهمگردانی کنید و با دنبال کردن مراحل این بخش، دوباره آن را آزمایش کنید.
استفاده مستقیم از ابزارهای خط فرمان
این مراحل را دنبال کنید تا تراز بخشهای ELF را مستقیماً بااستفاده از ابزارهای خط فرمان بررسی کنید:
- مطمئن شوید که هم Android SDK Build-Tools نسخه ۳۵.۰.۰ یا بالاتر و هم
Android NDK بااستفاده از مدیر SDK در Android Studio یا
ابزار خط فرمان
sdkmanagerنصب شده باشند. فایل APK برنامهتان را استخراج کنید:
Linux یا macOS
unzip APK_NAME.apk -d /tmp/my_apk_outWindows (PowerShell)
Expand-Archive -Path .\APK_NAME.apk -DestinationPath ~\tmp\my_apk_outدر فهرست راهنمای موقتی که فایل APK را در آن استخراج کردهاید، محتویات فهرست راهنمای
libرا برای فایلهای شیء همرسانیشده (.so) بررسی کنید. اینها همان فایلهای شیء مشترکی هستند که هنگام شناسایی کتابخانههای بومی بااستفاده از «تحلیلکننده APK» دیدهاید. فرمان زیر را در هر فایل شیء همرسانیشده اجرا کنید:Linux یا 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"در اینجا
SDK_ROOT_LOCATIONمسیر دایرکتوریای است که «کیت توسعه نرمافزار Android» را در آن نصب کردهاید،SHARED_OBJECT_FILEنام فایل شیء همرسانیشدهای است که بررسی میکنید، وNDK_VERSIONنسخه «کیت توسعه بومی Android» است که نصب کردهاید (برای مثال،28.0.12433566). برونداد برای هر فایل که بررسی میکنید چیزی شبیه به این خواهد بود: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**14خطوط برونداد را بررسی کنید تا مطمئن شوید بخشهای بار دارای مقادیر کمتر از
2**14نباشند. اگر هرکدام از بخشهای بارگذاری2**13،2**12، یا مقادیر پایینتر باشد، باید بستهبندی آن کتابخانهها را بهروز کنید، سپس برنامهتان را بازهمگردانی کنید و با دنبال کردن مراحل این بخش دوباره آزمایش کنید.سپس، ابزار خط فرمان
zipalignرا در فایل APK برنامهتان اجرا کنید:Linux یا 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.apkکه در آن
SDK_ROOT_LOCATIONمسیر دایرکتوریای است که کیت توسعه نرمافزار Android را در آن نصب کردهاید، وAPK_NAMEنام فایل APK برنامهتان است. اگر همه کتابخانههای مشترک بهدرستی تراز شده باشند، خط آخر خروجی عبارت «درستیسنجی موفقیتآمیز بود» را نشان میدهد.اگر درستیسنجی ناموفق بود، برخیاز کتابخانههای مشترک باید دوباره تراز شوند، بنابراین باید بستهبندی آن کتابخانهها را بهروز کنید، سپس برنامهتان را بازهمگردانی کنید و با دنبال کردن مراحل این بخش دوباره آن را آزمایش کنید.
بررسی پرچم امنیتی RELRO
برای کاهش سوءاستفادههای امنیتی، پیونددهندههای مدرن از پرچم Relocation Read-Only (RELRO) استفاده میکنند تا بخشهای جابهجایی فایل شیء مشترک را پساز بارگیری فقط خواندنی کنند. پرچم RELRO را در ساخت خود فعال کنید.
بخش RELRO که دارای نشانی شروع بهعلاوه اندازه بخش (MemSize) است که
تراز ۱۶ کیلوبایتی ندارد، برنامه را در زمان اجرا با خطای بخشبندی ازکار میاندازد. این اتفاق زمانی میافتد که فایل .so با زنجیره ابزار NDK نسخه r27 و پایینتر بدون فعال کردن پرچمهای مربوطه ساخته شده باشد.
فرمان زیر را روی هر فایل شیء همرسانیشده اجرا کنید (Linux یا 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'
اگر بخش RELRO وجود داشته باشد، رشته GNU_RELRO چاپ میشود.
سپس، تراز بخش RELRO را با جمع کردن نشانی آفست مجازی آن (VirtAddr) با اندازه حافظه بخش (MemSiz) و تقسیم کردن آن بر ۱۶ کیلوبایت (0x4000) بررسی کنید. اگر باقیمانده (پیمانه) صفر باشد، بخش RELRO با اندازه صفحه ۱۶ کیلوبایتی تراز است.
در اینجا مثالی از فایل .so غیرهمتراز آورده شده است:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x01510 R 0x1
فرمول: (VirtAddr + MemSiz) % 0x4000 == 0
نتیجه: (0xdfaf0 + 0x01510) % 0x4000 = 0xE1000 % 0x4000 == 0x1000
چون 0x1000 صفر نیست، این فایل .so با اندازه صفحه ۱۶ کیلوبایتی سازگار نیست. محدوده محافظت RELRO
از DC000 (صفحهشکنی قبلی) تا E4000 فقط خواندنی است،
اما پیونددهنده Android انتظار دارد زیرمحدوده از E1000 تا E4000
نوشتنی باشد، که منجر به خطای تقسیمبندی میشود. دراینصورت، فایل .so را طبق آنچه در بخش کامپایل کردن برنامه بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی شرح داده شده است دوباره بسازید.
در اینجا نمونهای از فایل .so تراز با بخش RELRO آورده شده است:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x00510 R 0x1
در اینجا نمونهای از فایل .so بدون بخش RELRO آورده شده است:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
این فایل .so بهطور بدیهی با ۱۶ کیلوبایت سازگار است و هیچ بخش RELRO ندارد.
در اینجا نمونهای از فایل .so ترازشده آورده شده است که در آن GNU_RELRO در بخش 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
فرمول: (VirtAddr + MemSiz) % 0x4000 == 0
نتیجه: (0x4680 + 0x0980) % 0x4000 = 0x5000 % 0x4000 == 0x1000
هرچند 0x1000 صفر نیست، اما این فایل .so همچنان با اندازه صفحه ۱۶ کیلوبایتی سازگار است.
فرمول پیمانهای زمانی اعمال میشود که GNU_RELRO بخش LOAD را با
دادههای نوشتنی بعدی (مثل .data یا .bss) همرسانی کند.
برای بررسی اینکه GNU_RELRO در بخش LOAD خود قرار دارد یا نه، با اجرای llvm-readelf -Wl و فیلتر کردن با grep 'LOAD\|RELRO\|Type'، سرایندهای برنامه را بازرسی کنید. VirtAddr و MemSiz مربوط به
GNU_RELRO را دربرابر بخش LOAD حاوی آن مقایسه کنید. در این مثال،
هر دو VirtAddr 0x4680 و MemSiz 0x0980 دارند.
چون کل بخش LOAD فقط حاوی دادههای RELRO است،
هیچ داده قابلنوشتنی در زیرمحدوده 0x5000 تا 0x8000 وجود ندارد. علاوهبراین، هر بخش LOAD قابلنوشتن بعدی در مرز صفحه ۱۶ کیلوبایتی جداگانهای (در 0x8000 یا فراتر از آن) شروع میشود. محافظت فقط خواندنی پیونددهنده با هیچیک از دادههای نوشتنی همپوشانی نخواهد داشت، بنابراین خطای تقسیمبندی رخ نمیدهد.
برنامهتان را با پشتیبانی از دستگاههای ۱۶ کیلوبایتی بسازید
اگر برنامهتان از کد بومی استفاده میکند، مراحل شرحدادهشده در بخشهای زیر را تکمیل کنید تا مطمئن شوید برنامهتان از دستگاههای ۱۶ کیلوبایتی پشتیبانی میکند:
- بستهبندی کتابخانههای مشترک را بهروز کنید
- کامپایل کردن برنامه بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی
- اصلاح کد و حل مشکلات زمان اجرا
- بهینهسازی تخصیصدهندههای حافظه سفارشی (درصورت وجود)
- بررسی کیتهای توسعه نرمافزار برای پشتیبانی از ۱۶ کیلوبایت
بستهبندی کتابخانههای مشترک را بهروز کنید
به AGP نسخه ۸.۵.۱ یا بالاتر ارتقا دهید و از کتابخانههای مشترک فشردهنشده استفاده کنید.
از bundletool برای بررسی تراز بودن زیپ استفاده کنید
برای دیدن تراز دسته، از این مورد استفاده کنید:
bundletool dump config --bundle=<my .aab> | grep alignment
اگر PAGE_ALIGNMENT_16K را میبینید، میدانید که درخواستهای دستهتان به تراز کردن فشرده ۱۶ کیلوبایتی نیاز دارد. اگر PAGE_ALIGNMENT_4K را میبینید، این دستورالعمل به APK ساختهشده از
این AAB میگوید که فایلهای .so تراز ۴ کیلوبایتی در فایل zip داشته باشد.
AGP نسخه ۸.۵.۱ یا بالاتر
دستگاههای ۱۶ کیلوبایتی به برنامههایی نیاز دارند که با کتابخانههای مشترک فشردهنشده عرضه میشوند تا آنها را در مرز تراز zip ۱۶ کیلوبایتی تراز کنند. برای انجام این کار، باید به «افزایه Android Gradle» (AGP) نسخه ۸.۵.۱ یا بالاتر ارتقا دهید. برای جزئیات مربوط به فرایند ارتقا، به بخش دستیار ارتقای افزایه Android Gradle مراجعه کنید.
AGP نسخه ۸.۵ یا پایینتر
اگر نمیتوانید AGP را به نسخه ۸.۵.۱ یا بالاتر ارتقا دهید، راه جایگزین این است که به استفاده از کتابخانههای مشترک فشردهشده تغییر دهید. پیکربندی Gradle را بهروز کنید تا Gradle کتابخانههای مشترک را هنگام بستهبندی برنامه فشرده کند تا از بروز مشکلات نصب برنامه با کتابخانههای مشترک ترازنشده جلوگیری شود.
شیک
در فایل build.gradle، گزینه زیر را اضافه کنید:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
کاتلین
در فایل build.gradle.kts، گزینه زیر را اضافه کنید:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
AGP نسخه ۸.۰ یا پایینتر
اگر از نسخه AGP برابر یا پایینتر از ۸.۰ استفاده میکنید، باید گزینه کتابخانه بومی فشردهنشده را برای «دستههای برنامه» در فایل gradle.properties غیرفعال کنید:
android.bundle.enableUncompressedNativeLibs=false
برنامهتان را بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی همگردانی کنید
برای اینکه برنامه شما در دستگاههای ۱۶ کیلوبایتی اجرا شود، بخشهای ELF کتابخانههای مشترک باید بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی بهدرستی ترازبندی شوند.
برای توسعهدهندگان بازی، اگر بازی شما روی موتور بازی Unity اجرا میشود، به راهنمای Unity مراجعه کنید. اگر بازیتان روی موتور بازی Unreal اجرا میشود، به راهنمای Unreal مراجعه کنید.برای موتورهای بازی بومی، این راهنما را ادامه دهید.
برای همگردانی کردن برنامهتان بااستفاده از ترازبندی ELF ۱۶ کیلوبایتی، مراحل یکی از بخشهای زیر را بسته به نسخه Android NDK که استفاده میکنید تکمیل کنید.
Android NDK r28 و بالاتر
نسخه NDK r28 و بالاتر بهطور پیشفرض با ترازبندی ۱۶ کیلوبایتی کامپایل میشوند.
Android NDK r27 و نسخههای پایینتر
برای پشتیبانی از همگردانی کتابخانههای مشترک ترازبندیشده ۱۶ کیلوبایتی با Android NDK نسخه r27 یا پایینتر، از پرچمهای پیونددهنده زیر استفاده کنید:
-Wl,-z,max-page-size=16384
-Wl,-z,common-page-size=16384
در اینجا نحوه بهروزرسانی فایلهای پیکربندی سیستم ساخت آورده شده است:
ndk-build
اگر از ndk-build استفاده میکنید، Android.mk را بهروز کنید تا چیدمان ۱۶ کیلوبایتی ELF را فعال کنید:
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
CMake
اگر از CMake استفاده میکنید، CMakeLists.txt را بهروز کنید تا چیدمان ELF با اندازه ۱۶ کیلوبایت فعال شود:
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-Wl,-z,max-page-size=16384"
"-Wl,-z,common-page-size=16384"
)
رفع مشکلات کد و حل مسائل زمان اجرا
حتی اگر برنامهتان با اندازه ۱۶ کیلوبایت ترازبندی شده باشد، اگر در بخشهایی از کدتان فرض شده باشد که دستگاه از اندازه صفحه خاصی استفاده میکند، ممکن است برنامهتان با خطا مواجه شود. برای جلوگیری از این مشکل، مراحل زیر را تکمیل کنید:
هرگونه وابستگی کدبندیشدهای را که به
PAGE_SIZEثابت یا نمونههای منطق کد شما که فرض میکنند اندازه صفحه دستگاه ۴ کیلوبایت است (4096) بردارید.درعوض از
getpagesize()یاsysconf(_SC_PAGESIZE)استفاده کنید.موارد استفاده از
mmap()و دیگر میاناهای برنامهسازی کاربردی را که به آرگومانهای همتراز با صفحه نیاز دارند پیدا کنید و درصورت لزوم آنها را با گزینههای جایگزین عوض کنید.
در برخی موارد، اگر برنامه شما از PAGE_SIZE بهعنوان مقدار مناسبی که به اندازه صفحه زیرین مرتبط نیست استفاده کند، در این صورت استفاده از آن در حالت ۱۶ کیلوبایتی باعث ازکار افتادن برنامه شما نخواهد شد. بااینحال، اگر این مقدار با mmap بدون MAP_FIXED به هسته ارسال شود، هسته همچنان از کل صفحه استفاده میکند که باعث هدر رفتن مقداری حافظه میشود. به این دلایل، وقتی حالت ۱۶ کیلوبایتی در NDK r27 و بالاتر فعال باشد، PAGE_SIZE تعریفنشده است.
اگر برنامهتان از PAGE_SIZE به این روش استفاده میکند و هرگز این مقدار را مستقیماً به هسته ارسال نمیکند، بهجای استفاده از PAGE_SIZE، متغیر جدیدی با نام جدید ایجاد کنید تا نشان دهد که برای اهداف دیگری استفاده میشود و نشاندهنده صفحه حافظه واقعی نیست.
بهینهسازی تخصیصدهندههای حافظه سفارشی
در سیستمهای ۱۶ کیلوبایتی، کوچکترین واحد حافظه فیزیکی که سیستمعامل اختصاص میدهد چهار برابر بزرگتر از سیستمهای ۴ کیلوبایتی است. اگر تخصیصدهنده سفارشی براساس فرضیههای ۴ کیلوبایتی طراحی شده باشد، میتواند اشیای کوچک را در چندین صفحه ۱۶ کیلوبایتی پراکنده کند و حافظه خالی را بهطور غیرضروری حفظ کند. این کار میتواند استفاده از حافظه فیزیکی (RSS) را بهطور قابلتوجهی افزایش دهد و کارایی مبادله فشردهشده (ZRAM) را کاهش دهد.
اگر کد شما استخرهای حافظه خود را مدیریت میکند، این توصیهها را دنبال کنید:
۱. از آستانههای بایت کدگذاریشده برای آزاد کردن حافظه اجتناب کنید
بسیاریاز تخصیصدهندهها از محدودیتهای بایت ثابت استفاده میکنند تا تصمیم بگیرند چه زمانی حافظه را بااستفاده از madvise(MADV_DONTNEED) به سیستمعامل برگردانند (برای مثال، فقط درصورتی حافظه را آزاد میکنند که اشیای فعال کمتر از ۸ کیلوبایت را اشغال کنند).
در سیستم ۱۶ کیلوبایتی، حتی یک شیء زنده ۱۶ بایتی کل صفحه ۱۶ کیلوبایتی (که بزرگتر از ۸ کیلوبایت است) را سنجاق میکند. درنتیجه، آستانه انتشار هرگز برآورده نمیشود و تخصیصدهنده هرگز حافظه استفادهنشده اطراف را به هسته برنمیگرداند.
چه کاری باید انجام دهید: هرگز از ثابتهای بایت کدبندیشده سخت برای اکتشافات انتشار صفحه استفاده نکنید.
آستانههای انتشار مقیاس را بهطور پویا در زمان اجرا براساس اندازه واقعی صفحه
بااستفاده از sysconf(_SC_PAGESIZE) تغییر دهید.
۲. ابتدا صفحههایی که قبلاً استفاده شدهاند پر شود (تخصیص ابتدا-متراکم)
اگر تخصیصدهنده حافظه را بهترتیب خروج بهترتیب ورود (FIFO) یا نوبتی توزیع کند، تخصیصهای جدید در بسیاری از صفحههای ۱۶ کیلوبایتی که تاحدی پر شدهاند پراکنده میشوند. یک شیء منفرد در صفحه باعث میشود همه ۱۶ کیلوبایت در «حافظه دسترسی تصادفی» فیزیکی مقیم بماند.
چه باید کرد: همیشه پیشاز دست زدن به صفحههای خالی یا کماستفاده، اشیا جدید را از پرترین (متراکمترین) صفحه یا برگه اختصاص دهید. متمرکز کردن تخصیصهای جدید روی صفحههای ازقبل کثیف به صفحههایی که بهندرت استفاده میشوند اجازه میدهد بهطور طبیعی به صفر شیء فعال برسند، بنابراین کل صفحه ۱۶ کیلوبایتی میتواند به سیستمعامل واگذار شود.
۳. مجموعههای حافظه را با ۱۶ کیلوبایت تراز کنید و اندازه مجموعهها را در حد متوسط نگه دارید
گسترههای چندصفحهای که برای سیستمهای ۴ کیلوبایتی طراحی شدهاند میتوانند فضای ذخیره حافظه آزاد نشده اضافی در هستههای ۱۶ کیلوبایتی داشته باشند. علاوهبراین، کلاسهای اندازه که بهطور یکنواخت به ۱۶ کیلوبایت تقسیم نمیشوند، باعث تکهتکه شدن در انتهای هر صفحه میشوند.
کاری که باید انجام دهید:
- مطمئن شوید همه استخرهای حافظه، مرزهای اسلب، و ترازهای میانگیر مضربهای دقیقی از اندازه صفحه زمان اجرا باشند.
- اندازههای گستره چندصفحهای را برای کلاسهای شیء کوچک دوباره ارزیابی کنید تا از اختصاص دادن قطعههای بسیار بزرگ که حافظه غیرفعال را بهدام میاندازند جلوگیری شود.
۴. حافظه فیزیکی را برای بافرهای بزرگ ذخیرهشده در حافظه نهان فوراً آزاد کنید
تخصیصدهندههای سفارشی اغلب میانگیرهای بزرگ (بیشتر از ۶۴ کیلوبایت) را در یک استخر درونحافظهای ذخیره میکنند تا بتوانند بدون پرداخت هزینه سربار فراخوانیهای سیستم mmap یا munmap دوباره از آنها استفاده کنند. بااینحال، نگهداشتن این میانگیرهای کثیف در حافظه، مگابایتها از
RAM فیزیکی را درحین انتظار برای زمانسنج تخلیه هدر میدهد.
کار لازم: محدوده نشانی حافظه مجازی را برای استفاده مجدد سریع رزرو کنید،
اما وقتی بافر را به حافظه نهان برمیگردانید، بلافاصله madvise(..., MADV_DONTNEED) یا madvise(..., MADV_FREE) را فراخوانی کنید. سیستمعامل بلافاصله RAM فیزیکی را پس میگیرد، درحالیکه برنامه شما همچنان میتواند فوراً از نشانی مجازی بدون تخصیص مجدد استفاده کند.
۵. صفر کردن حافظه در فضای آزاد بهجای تخصیص برای فشردهسازی ZRAM
Android از فضای مبادله فشرده (ZRAM) برای نگه داشتن برنامههای پسزمینه در حافظه استفاده میکند. در دستگاههای ۱۶ کیلوبایتی، اگر صفحهای حتی یک شیء زنده داشته باشد، کل صفحه ۱۶ کیلوبایتی مقیم میماند یا به ZRAM مبادله میشود. دادههای مزاحم باقیمانده (مثل اشارهگرها و رشتههای قدیمی) در بخشهای قبلاً آزادشده آن صفحه بهخوبی فشرده نمیشود.
اگر تخصیصدهنده شما حافظه را صفر میکند (مثلاً برای امنیت یا تخصیصهای صفر-مقداردهیشده)، بهتر است هنگام لغو تخصیص (free()) حافظه را صفر کنید نه هنگام تخصیص:
- صفحههای سنجاقشده هزینه کمتری دارند: حافظه غیرفعال در صفحههای ۱۶ کیلوبایتی که تاحدی پر شدهاند در ZRAM تقریباً به صفر فشرده میشود، بنابراین صفحههای سنجاقشده فضای مبادله فیزیکی را هدر نمیدهند.
- سربار حافظه نهان کمینه: در زمانی که
free()فراخوانی میشود، حافظه ازقبل در حافظه نهان CPU داغ است و از خطاهای حافظه نهان اضافی در آینده جلوگیری میکند.
خلاصه توصیهها
| مساحت | توصیه | تأثیر موردانتظار |
|---|---|---|
| آستانههای پاکسازی | آستانههای انتشار را بهطور پویا بااستفاده از sysconf(_SC_PAGESIZE) مقیاسبندی کنید. |
از بنبست دائمی منطق انتشار جلوگیری میکند. |
| سفارش تخصیص | ابتدا از متراکمترین (تقریباً پر) صفحه یا دال اختصاص دهید. | با بستهبندی اشیای فعال باهم، حافظه مقیم (RSS) را کاهش میدهد. |
| اندازهگیری بازه | کلاسهای اندازه را با مضربهای ۱۶ کیلوبایت تراز کنید و از دالهای بیشازاندازه بزرگ اجتناب کنید. | تکهتکهسازی صفحه پایانی را حذف میکند و فضای خالی حافظه را کاهش میدهد. |
| میانگیری حافظههای نهان | هنگام ذخیره کردن میانگیرهای بزرگ، بلافاصله madvise(MADV_DONTNEED) را فراخوانی کنید. |
تورم RAM غیرفعال را حذف میکند و درعینحال استفاده مجدد مجازی سریع را حفظ میکند. |
| Swap / ZRAM | حافظه را بهجای تخصیص، در free() صفر کنید. |
نسبتهای فشردهسازی ZRAM را بهبود میبخشد تا صفحات سنجاقشده هزینه کمتری داشته باشند. |
بررسی کیتهای توسعه نرمافزار برای پشتیبانی از ۱۶ کیلوبایت
بسیاری از کیتهای توسعه نرمافزار با اندازه صفحه ۱۶ کیلوبایتی سازگار هستند، بهویژه اگر خودتان آنها را بسازید یا نسخههای پیشساخته اخیر را دریافت کنید. بااینحال، ازآنجاییکه برخیاز پیشساختهای کیت توسعه نرمافزار یا نسخههای کیت توسعه نرمافزار با ۱۶ کیلوبایت سازگار نیستند، باید وبسایت هر ارائهدهنده کیت توسعه نرمافزار را بررسی کنید تا مشخص شود از کدام نسخه باید با ۱۶ کیلوبایت استفاده کنید.
آزمایش کردن برنامه در محیط ۱۶ کیلوبایتی
پساز ساختن برنامه با پشتیبانی از دستگاههای ۱۶ کیلوبایتی، باید برنامه را در محیط ۱۶ کیلوبایتی آزمایش کنید تا ببینید آیا برنامه دچار پسرفت میشود یا نه. برای انجام این کار، این مراحل را دنبال کنید:
کیت توسعه نرمافزار Android 15 یا بالاتر را راهاندازی کنید.
یکی از محیطهای آزمایشی زیر را راهاندازی کنید:
- راهاندازی کردن «شبیهساز Android» با تصویر سیستم Android 15 مبتنی بر ۱۶ کیلوبایت
- استفاده از Cuttlefish با اندازه صفحه ۱۶ کیلوبایت در ARM64
- شبیهسازی Cuttlefish با اندازه صفحه ۱۶ کیلوبایت در x86-64
- فعال کردن حالت ۱۶ کیلوبایتی در دستگاه بااستفاده از گزینههای توسعهدهندگان
- استفاده از Samsung Remote Test Lab در دستگاههای پشتیبانیکننده از ۱۶ کیلوبایت
دستگاه آزمایشیتان را راهاندازی کنید، سپس فرمان زیر را اجرا کنید تا مطمئن شوید از محیط ۱۶ کیلوبایتی استفاده میکند:
adb shell getconf PAGE_SIZEفرمان باید مقدار
16384را برگرداند.فرمان
zipalignزیر را اجرا کنید تا مطمئن شوید برنامهتان ۱۶ کیلوبایت تراز است، که در آن APK_NAME نام فایل APK برنامهتان است:zipalign -c -P 16 -v 4 APK_NAME.apkبرنامهتان را بهطور کامل آزمایش کنید و روی بخشهایی که ممکن است تحتتأثیر تغییر نمونههای کد که به اندازههای صفحه خاصی ارجاع میدهند قرار بگیرند تمرکز کنید.
راهاندازی «شبیهساز Android» با تصویر سیستم مبتنی بر ۱۶ کیلوبایت
برای راهاندازی محیط ۱۶ کیلوبایتی بااستفاده از «شبیهساز Android»، این مراحل را دنبال کنید:
- در Android Studio، روی ابزارها > مدیر SDK کلیک کنید.
در برگه پلاتفرمهای کیت توسعه نرمافزار، نمایش جزئیات بسته را انتخاب کنید، سپس بخش Android VanillaIceCream یا بالاتر را ازهم باز کنید و یک یا هر دو تصویر سیستم شبیهساز زیر را بسته به دستگاههای مجازیای که میخواهید ایجاد کنید انتخاب کنید:
- Google APIs Experimental 16 KB Page Size ARM 64 v8a System Image
- Google APIs Experimental 16 KB Page Size Intel x86_64 Atom System Image
روی اعمال > تأیید کلیک کنید تا هرکدام از ایمیجهای سیستم را که انتخاب کردهاید بارگیری کنید.
مراحل راهاندازی دستگاه مجازی برای Android 15 را دنبال کنید و وقتی از شما خواسته شد ایمیج سیستم را انتخاب کنید، ایمیج سیستم ۱۶ کیلوبایتی را که بارگیری کردهاید انتخاب کنید. اگر بهطور خودکار توصیه نشد، میتوانید ایمیج سیستم ۱۶ کیلوبایتی را در برگه ایمیجهای دیگر پیدا کنید.
راهاندازی شبیهساز
پساز تکمیل راهاندازی «شبیهساز Android» و دستگاههای مجازی، شبیهساز را از منو دستگاه هدف یا از خط فرمان راهاندازی کنید.
فعال کردن حالت ۱۶ کیلوبایت روی دستگاه با استفاده از گزینههای توسعهدهنده

برای بوت کردن دستگاه در حالت ۱۶ کیلوبایت، گزینه توسعهدهنده Boot with 16KB page size را فعال یا غیرفعال کنید.
در نسخههای QPR اندروید ۱۵، میتوانید از گزینه توسعهدهنده که در دستگاههای خاصی موجود است، برای بوت کردن دستگاه در حالت ۱۶ کیلوبایت و انجام آزمایش روی دستگاه استفاده کنید . قبل از استفاده از گزینه توسعهدهنده، به تنظیمات > سیستم > بهروزرسانیهای نرمافزار بروید و هرگونه بهروزرسانی موجود را اعمال کنید.
این گزینه توسعهدهنده در دستگاههای زیر موجود است:
پیکسل ۸ و ۸ پرو (با اندروید ۱۵ QPR1 یا بالاتر)
پیکسل ۸a (با اندروید ۱۵ QPR1 یا بالاتر)
پیکسل ۹، ۹ پرو و ۹ پرو ایکسال (با اندروید ۱۵ نسخه QPR2 یا بالاتر)
پیکسل ۹a (با اندروید ۱۶ یا بالاتر)
حالت سازگاری با نسخههای قدیمی ۱۶ کیلوبایتی
هشدار در حالت سازگاری با اندازه صفحه
گزینه سازگاری معکوس ۱۶ کیلوبایتی زمانی دردسترس است که دستگاه با هسته ۱۶ کیلوبایتی اجرا شود. وقتی شرایط زیر برقرار باشد، مدیر بسته برنامه را در حالت سازگاری با گذشته ۱۶ کیلوبایتی اجرا میکند:
- اگر برنامه فایلهای ELF (با پسوند
.so) با بخش LOAD تراز ۴ کیلوبایتی داشته باشد. - اگر فایل APK فشردهشده دارای فایلهای ELF فشردهنشدهای باشد که ۴ کیلوبایت تراز ZIP داشته باشد.
اگر مدیر بسته حالت سازگاری معکوس ۱۶ کیلوبایتی را برای برنامهای فعال کرده باشد، برنامه هنگام اولین راهاندازی هشداری نمایش میدهد که میگوید در حالت سازگاری معکوس ۱۶ کیلوبایتی اجرا میشود.
حالت سازگاری با گذشته ۱۶ کیلوبایتی به برخیاز برنامهها اجازه میدهد کار کنند، اما برای بهترین قابلیت اطمینان و پایداری، برنامهها همچنان باید ۱۶ کیلوبایتی تراز شوند.
در صفحه اطلاعات برنامه، در بخش پیشرفته، تنظیم اجرای برنامه در حالت سازگاری با اندازه صفحه را روشن یا خاموش کنید تا حالت سازگاری با نسخههای قدیمی ۱۶ کیلوبایتی برای برنامه خاصی فعال یا غیرفعال شود. این تنظیم فقط زمانی قابلمشاهده است که دستگاه با اندازه صفحه ۱۶ کیلوبایتی درحال اجرا باشد.
تنظیم حالت سازگاری با اندازه صفحه
برای اجباری کردن روشن بودن سازگاری با نسخههای قبلی ۱۶ کیلوبایتی برای همه برنامههای دستگاه:
adb shell setprop bionic.linker.16kb.app_compat.enabled true
adb shell setprop pm.16kb.app_compat.disabled false
برای خاموش کردن اجباری سازگاری عقبرو ۱۶ کیلوبایتی برای همه برنامههای دستگاه:
adb shell setprop bionic.linker.16kb.app_compat.enabled false
adb shell setprop pm.16kb.app_compat.disabled true
در Android 17، همچنین میتوانید سازگاری معکوس ۱۶ کیلوبایتی را برای همه برنامهها بهاجبار خاموش کنید و باعث شوید هر باینری ناسازگار فوراً لغو شود:
adb shell setprop bionic.linker.16kb.app_compat.enabled fatal
adb shell setprop pm.16kb.app_compat.disabled true
برای روشن یا خاموش کردن حالت سازگاری با نسخههای قبلی برای برنامهای خاص در AndroidManifest.xml آن، ویژگی android:pageSizeCompat را روی فعال یا غیرفعال تنظیم کنید. وقتی این ویژگی تنظیم شود، برنامه هنگام راهاندازی هشدارهای حالت سازگاری با نسخههای قدیمی را نمایش نخواهد داد.