في السابق، كان نظام التشغيل Android يتيح فقط صفحات الذاكرة بحجم 4 كيلوبايت، ما ساعد في تحسين أداء ذاكرة النظام بما يتناسب مع إجمالي مساحة الذاكرة التي كانت تتوفّر عادةً في أجهزة Android. بدءًا من الإصدار 15 من نظام التشغيل Android، يتيح مشروع Android مفتوح المصدر (AOSP) استخدام الأجهزة التي تم ضبطها لاستخدام حجم صفحة يبلغ 16 كيلوبايت (أجهزة 16 كيلوبايت). إذا كان تطبيقك يستخدم أي مكتبات NDK، سواء بشكل مباشر أو غير مباشر من خلال حزمة تطوير برامج (SDK)، عليك إعادة إنشاء تطبيقك لكي يعمل على هذه الأجهزة التي تستخدم صفحات ذاكرة بحجم 16 كيلوبايت.
مع استمرار الشركات المصنّعة للأجهزة في تصميم أجهزة تتضمّن كميات أكبر من الذاكرة الفعلية (RAM)، ستستخدم العديد من هذه الأجهزة أحجام صفحات تبلغ 16 كيلوبايت (وأكبر في النهاية) لتحسين أداء الجهاز. تتيح إضافة دعم للأجهزة التي تستخدم صفحات بحجم 16 كيلوبايت تشغيل تطبيقك على هذه الأجهزة، كما تساعد تطبيقك في الاستفادة من التحسينات المرتبطة بالأداء. وبدون إعادة تجميع، لن تعمل التطبيقات على الأجهزة التي تستخدم صفحات الذاكرة بحجم 16 كيلوبايت في إصدارات Android المستقبلية.
لمساعدتك في إضافة إمكانية استخدام تطبيقك، قدّمنا إرشادات حول كيفية التحقّق مما إذا كان تطبيقك سيتأثر، وكيفية إعادة إنشاء تطبيقك (إذا كان ذلك منطبقًا)، وكيفية اختبار تطبيقك في بيئة بحجم 16 كيلوبايت باستخدام المحاكيات (بما في ذلك صور نظام Android 15 لمحاكي Android).
متطلبات التوافق مع Google Play
لضمان عمل تطبيقك بشكل صحيح على أحدث إصدارات Android، يجب أن تتوافق جميع التطبيقات التي تستهدف الإصدار Android 15 (مستوى واجهة برمجة التطبيقات 35) والإصدارات الأحدث مع صفحات الذاكرة بحجم 16 كيلوبايت على الأجهزة التي تعمل بنظام 64 بت على Google Play. اعتبارًا من 1 شباط (فبراير) 2027، إذا كانت تحديثات تطبيقك لا تتوافق مع صفحات الذاكرة بحجم 16 كيلوبايت، فلن يكون بإمكانك طرح هذه التحديثات.
المزايا وتحسين الأداء
تستهلك الأجهزة التي تم ضبطها على أحجام صفحات تبلغ 16 كيلوبايت مساحة أكبر قليلاً من الذاكرة في المتوسط، لكنها تُجري أيضًا تحسينات متنوعة في الأداء لكل من النظام والتطبيقات:
- أوقات تشغيل التطبيق أقل عندما يكون النظام تحت ضغط الذاكرة: 3.16% انخفاضًا في المتوسط، مع تحسينات أكثر أهمية (تصل إلى %30) لبعض التطبيقات التي اختبرناها
- انخفاض في استهلاك الطاقة أثناء تشغيل التطبيق: انخفاض بنسبة% 4.56 في المتوسّط
- تشغيل أسرع للكاميرا: عمليات تشغيل أسرع بنسبة 4.48% في المتوسط، وعمليات تشغيل على البارد أسرع بنسبة 6.60% في المتوسط
- مدة تشغيل النظام المحسَّنة: تحسّنت بنسبة %8 (950 ملي ثانية تقريبًا) في المتوسّط
تستند هذه التحسينات إلى اختبارنا الأوّلي، ومن المرجّح أن تختلف النتائج على الأجهزة الفعلية. وسنقدّم تحليلاً إضافيًا للفوائد المحتملة للتطبيقات أثناء مواصلة الاختبار.
التحقّق مما إذا كان تطبيقك متأثرًا
إذا كان تطبيقك يستخدم أي رموز برمجية أصلية، عليك إعادة إنشاء تطبيقك ليتوافق مع الأجهزة التي تستخدم صفحات ذاكرة بحجم 16 كيلوبايت. إذا لم تكن متأكدًا مما إذا كان تطبيقك يستخدم رمزًا برمجيًا أصليًا، يمكنك استخدام "أداة تحليل حِزم APK" لتحديد ما إذا كان هناك أي رمز برمجي أصلي، ثم التحقّق من توافق أقسام ELF مع أي مكتبات مشتركة تجدها. يوفّر "استوديو Android" أيضًا ميزات تساعدك في رصد مشاكل المحاذاة تلقائيًا.
إذا كان تطبيقك يستخدم فقط الرموز البرمجية المكتوبة بلغة البرمجة Java أو Kotlin، بما في ذلك جميع المكتبات أو حِزم تطوير البرامج (SDK)، يكون تطبيقك متوافقًا مع الأجهزة التي تبلغ سعتها 16 كيلوبايت. ومع ذلك، ننصحك باختبار تطبيقك في بيئة بحجم 16 كيلوبايت للتأكّد من عدم حدوث أي تراجع غير متوقّع في سلوك التطبيق.
هل يستخدم تطبيقك رمزًا برمجيًا أصليًا؟
يستخدم تطبيقك الرمز البرمجي الأصلي إذا كان أيّ مما يلي منطبقًا:
- يستخدم تطبيقك أي رمز C/C++ (أصلي). إذا كان تطبيقك يستخدم Android NDK، فهذا يعني أنّه يستخدم الرمز البرمجي الأصلي.
- يربط تطبيقك بأي مكتبات أو ملحقات أصلية تابعة لجهات خارجية (مثل حِزم تطوير البرامج) تستخدمها.
- تم إنشاء تطبيقك باستخدام أداة إنشاء تطبيقات تابعة لجهة خارجية تستخدم مكتبات مجمّعة من رموز برمجية أصلية على الجهاز.
تحديد المكتبات المجمّعة من رموز برمجية أصلية باستخدام "أداة تحليل ملفات APK"
أداة تحليل ملفات APK هي أداة تتيح لك تقييم جوانب مختلفة من حِزمة APK تم إنشاؤها. للتأكّد ممّا إذا كان تطبيقك يستخدم رموزًا برمجية أصلية (بغض النظر عمّا إذا كانت متوافقة مع الصفحات بحجم 16 كيلوبايت):
- افتح استوديو Android، ثم انقر على ملف > فتح واختَر أي مشروع.
من شريط القوائم، انقر على إنشاء > تحليل حزمة APK...
اختَر حزمة APK التي تريد تحليلها.
ابحث داخل المجلد
libالذي يستضيف ملفات الكائنات المشتركة (.so) إذا كانت متوفرة. إذا كانت هناك أي ملفات كائنات مشتركة، سيستخدم تطبيقك الرمز البرمجي الأصلي. يعرض عمود المحاذاة رسائل تحذيرية لأي ملفات تتضمّن مشاكل في المحاذاة. إذا لم تكن هناك ملفات كائنات مشتركة أو لم يكن هناك مجلدlib، يعني ذلك أنّ تطبيقك لا يستخدم الرمز البرمجي الأصلي.
رصد مشاكل المحاذاة من خلال عمليات التحقّق الآلية
يُصدر "استوديو Android" تحذيرًا بشكل استباقي إذا كانت المكتبات أو حِزم APK المُنشأة مسبقًا غير متوافقة مع الحد الأدنى لحجم الملفات وهو 16 كيلوبايت. استخدِم أداة محلّل حِزم APK لمراجعة المكتبات التي يجب تحديثها أو لمعرفة ما إذا كانت هناك أي تغييرات مطلوبة في الرموز.
تُبرز أداة Lint في "استوديو Android" أيضًا المكتبات الأصلية التي لم تتم محاذاتها مع صفحة الذاكرة بحجم 16 كيلوبايت.
التحقّق من محاذاة أقسام ELF للمكتبات المشترَكة
بالنسبة إلى أي مكتبات مشترَكة، تأكَّد من أنّ أقسام ELF في المكتبات المشترَكة تتم محاذاتها بشكل صحيح باستخدام محاذاة ELF بحجم 16 كيلوبايت. إذا كنت تطوّر على نظام التشغيل 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يعرض النص البرمجي إما
ALIGNEDأوUNALIGNEDلجميع المكتبات المشتركةarm64-v8a.إذا كانت أي مكتبات مشترَكة
arm64-v8aأوx86_64UNALIGNED، عليك تعديل حزمة هذه المكتبات، ثم إعادة تجميع تطبيقك وإعادة الاختبار باتّباع الخطوات الواردة في هذا القسم.
استخدام أدوات سطر الأوامر مباشرةً
اتّبِع الخطوات التالية للتحقّق من محاذاة أقسام ELF باستخدام أدوات سطر الأوامر مباشرةً:
- تأكَّد من تثبيت الإصدار 35.0.0 أو إصدار أحدث من أدوات إنشاء حزمة تطوير البرامج (SDK) لنظام التشغيل Android وحزمة Android NDK باستخدام أداة SDK Manager في "استوديو Android" أو أداة سطر الأوامر
sdkmanager. استخرِج ملف APK لتطبيقك باتّباع الخطوات التالية:
Linux أو macOS
unzip APK_NAME.apk -d /tmp/my_apk_outنظام التشغيل Windows (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 LOADنظام التشغيل Windows (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هو مسار الدليل الذي ثبّت فيه حزمة تطوير البرامج (SDK) لنظام التشغيل Android، وSHARED_OBJECT_FILEهو اسم ملف العنصر المشترَك الذي تتحقّق منه، وNDK_VERSIONهو إصدار Android NDK الذي ثبّته (على سبيل المثال،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.apkنظام التشغيل Windows (PowerShell)
SDK_ROOT_LOCATION\Android\sdk\build-tools\35.0.0\zipalign.exe -v -c -P 16 4 APK_NAME.apkحيث يمثّل
SDK_ROOT_LOCATIONمسار الدليل الذي ثبَّت فيه حزمة تطوير البرامج (SDK) لنظام التشغيل Android، ويمثّلAPK_NAMEاسم ملف APK الخاص بتطبيقك. سيعرض السطر الأخير من الناتج عبارة "تم التحقّق بنجاح" إذا كانت جميع المكتبات المشترَكة متوافقة بشكل صحيح.إذا تعذّر إثبات صحة التوقيع، يجب إعادة ضبط بعض المكتبات المشترَكة، لذا عليك تعديل حِزم هذه المكتبات، ثم إعادة تجميع تطبيقك وإعادة الاختبار باتّباع الخطوات الواردة في هذا القسم.
التحقّق من علامة أمان RELRO
للحدّ من استغلال الثغرات الأمنية، تستخدم أدوات الربط الحديثة العلامة Relocation Read-Only (RELRO) لجعل أقسام النقل في ملف الكائن المشترَك للقراءة فقط بعد التحميل. فعِّل علامة RELRO في الإصدار.
يؤدي قسم RELRO الذي يتضمّن عنوان بدء بالإضافة إلى حجم القسم (MemSize) غير المحاذي إلى 16 كيلوبايت إلى تعطُّل التطبيق في وقت التشغيل بسبب خطأ في التقسيم. يحدث ذلك إذا تم إنشاء ملف .so باستخدام سلسلة أدوات NDK الإصدار 27 أو إصدار أقدم بدون تفعيل العلامات ذات الصلة.
نفِّذ الأمر التالي على كل ملف كائن مشترك (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'
تتم طباعة السلسلة GNU_RELRO إذا كان هناك قسم RELRO.
بعد ذلك، تحقَّق من محاذاة مقطع RELRO من خلال جمع عنوان الإزاحة الافتراضية (VirtAddr) مع حجم ذاكرة المقطع (MemSiz) وتقسيم الناتج على 16 كيلوبايت (0x4000). إذا كان باقي القسمة (modulo) صفرًا، يعني ذلك أنّ قسم RELRO تمت محاذاته مع 16 كيلوبايت.
في ما يلي مثال على ملف .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 ليس صفرًا، فإنّ libbad.so غير متوافق مع الصفحة بحجم 16 كيلوبايت. نطاق الحماية RELRO من DC000 (فاصل الصفحات السابق) إلى E4000 هو للقراءة فقط، ولكن Android Linker يتوقّع أن يكون النطاق الفرعي من E1000 إلى E4000 قابلاً للكتابة، ما يؤدي إلى حدوث خطأ تجزئة. في هذه الحالة، أعِد إنشاء ملف .so كما هو موضّح في قسم تجميع تطبيقك باستخدام محاذاة ELF بحجم 16 كيلوبايت.
في ما يلي مثال على ملف .so متوافق مع RELRO:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x00510 R 0x1
إنشاء تطبيقك ليتوافق مع الأجهزة التي تستخدم صفحات الذاكرة بحجم 16 كيلوبايت
إذا كان تطبيقك يستخدم رموزًا برمجية أصلية، عليك إكمال الخطوات الموضّحة في الأقسام التالية للتأكّد من أنّ تطبيقك متوافق مع الأجهزة التي تستخدم صفحات ذاكرة بحجم 16 كيلوبايت:
- تعديل حِزم المكتبات المشتركة
- تجميع تطبيقك باستخدام محاذاة ELF بحجم 16 كيلوبايت
- إصلاح الرمز وحلّ المشاكل أثناء التشغيل
- تحسين أدوات تخصيص الذاكرة المخصّصة (إن وُجدت)
- التحقّق من توافق حِزم تطوير البرامج (SDK) مع صفحة الذاكرة بحجم 16 كيلوبايت
تعديل حِزم المكتبات المشترَكة
ننصحك بالترقية إلى الإصدار 8.5.1 أو إصدار أحدث من "المكوّن الإضافي لنظام Gradle المتوافق مع Android" واستخدام المكتبات المشترَكة غير المضغوطة.
استخدِم bundletool للتحقّق من محاذاة الرمز البريدي
للاطّلاع على محاذاة الحزمة، استخدِم ما يلي:
bundletool dump config --bundle=<my .aab> | grep alignment
إذا ظهرت لك PAGE_ALIGNMENT_16K، يعني ذلك أنّ حزمة التطبيق تتطلّب محاذاة zip بحجم 16 كيلوبايت. إذا رأيت PAGE_ALIGNMENT_4K، يعني ذلك أنّ حزمة APK التي تم إنشاؤها من حزمة AAB هذه يجب أن تتضمّن ملفات .so متوافقة بحجم 4 كيلوبايت في ملف ZIP.
الإصدار 8.5.1 أو الإصدارات الأحدث من "المكوّن الإضافي لنظام Gradle المتوافق مع Android"
تتطلّب الأجهزة التي تستخدم صفحات بحجم 16 كيلوبايت أن تعمل التطبيقات التي تتضمّن مكتبات مشتركة غير مضغوطة على محاذاتها على حدود متوافقة مع تنسيق zip بحجم 16 كيلوبايت. لإجراء ذلك، عليك الترقية إلى الإصدار 8.5.1 أو إصدار أحدث من "المكوّن الإضافي لنظام Gradle المتوافق مع Android" (AGP). راجِع القسم أداة مساعدة لترقية المكوّن الإضافي لنظام Gradle المتوافق مع Android للحصول على تفاصيل حول عملية الترقية.
الإصدار 8.5 أو الإصدارات الأقدم من "مكوّن Android الإضافي"
إذا لم تتمكّن من ترقية "المكوّن الإضافي لنظام Gradle المتوافق مع Android" إلى الإصدار 8.5.1 أو إصدار أحدث، يمكنك بدلاً من ذلك التبديل إلى استخدام المكتبات المشترَكة المضغوطة. عدِّل إعدادات Gradle لكي يضغط Gradle المكتبات المشتركة عند حزم تطبيقك لتجنُّب حدوث مشاكل في تثبيت التطبيق بسبب المكتبات المشتركة غير المتوافقة.
أنيق
في ملف build.gradle، أضِف الخيار التالي:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
Kotlin
في ملف build.gradle.kts، أضِف الخيار التالي:
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
الإصدار 8.0 أو الإصدارات الأقدم من "مكوّن Android الإضافي"
إذا كنت تستخدم إصدارًا من "المكوّن الإضافي لنظام Gradle المتوافق مع Android" (AGP) يساوي 8.0 أو إصدارًا أقدم، عليك أيضًا إيقاف خيار "المكتبة غير المضغوطة المجمّعة من رموز برمجية أصلية" لحِزم التطبيقات في ملف gradle.properties:
android.bundle.enableUncompressedNativeLibs=false
تجميع تطبيقك باستخدام محاذاة ELF بحجم 16 كيلوبايت
تتطلّب الأجهزة التي تبلغ سعة صفحات الذاكرة فيها 16 كيلوبايت محاذاة مقاطع ELF الخاصة بالمكتبات المشتركة بشكل صحيح باستخدام محاذاة ELF بحجم 16 كيلوبايت لكي يتمكّن تطبيقك من العمل.
بالنسبة إلى مطوّري الألعاب، إذا كانت لعبتك تعمل على محرّك ألعاب Unity، يُرجى الرجوع إلى دليل Unity. إذا كانت لعبتك تعمل على محرّك ألعاب Unreal، يُرجى الرجوع إلى دليل Unreal.أما إذا كنت تستخدم محرّكات ألعاب أصلية، فتابِع قراءة هذا الدليل.
لتجميع تطبيقك باستخدام محاذاة ELF بحجم 16 كيلوبايت، أكمل الخطوات الواردة في أحد الأقسام التالية حسب إصدار Android NDK الذي تستخدمه.
Android NDK r28 والإصدارات الأحدث
يتم تجميع الإصدار r28 من NDK والإصدارات الأحدث مع محاذاة 16 كيلوبايت تلقائيًا.
Android NDK r27 والإصدارات الأقدم
لإتاحة تجميع المكتبات المشترَكة المتوافقة مع 16 كيلوبايت باستخدام الإصدار 27 أو إصدار أقدم من Android NDK، استخدِم علامات الرابط التالية:
-Wl,-z,max-page-size=16384
-Wl,-z,common-page-size=16384
في ما يلي كيفية تعديل ملفات إعداد نظام التصميم:
ndk-build
إذا كنت تستخدم ndk-build، عدِّل Android.mk لتفعيل محاذاة ملفات ELF بحجم 16 كيلوبايت:
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
CMake
إذا كنت تستخدم CMake، عدِّل CMakeLists.txt لتفعيل محاذاة ELF بحجم 16 كيلوبايت
على النحو التالي:
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-Wl,-z,max-page-size=16384"
"-Wl,-z,common-page-size=16384"
)
إصلاح الرمز وحلّ المشاكل أثناء التشغيل
حتى إذا كان تطبيقك متوافقًا مع صفحة الذاكرة بحجم 16 كيلوبايت، قد يواجه أخطاء إذا افترضت بعض أجزاء الرمز البرمجي أنّ الجهاز يستخدم حجم صفحة معيّنًا. لتجنُّب ذلك، أكمِل الخطوات التالية:
أزِل أي تبعيات مبرمَجة بشكل ثابت تشير إلى الثابت
PAGE_SIZEأو أي مثيلات في منطق الرمز البرمجي تفترض أنّ حجم صفحة الجهاز هو 4 كيلوبايت (4096).يُرجى استخدام
getpagesize()أوsysconf(_SC_PAGESIZE)بدلاً من ذلك.ابحث عن استخدامات
mmap()وغيرها من واجهات برمجة التطبيقات التي تتطلّب وسيطات متوافقة مع الصفحة، واستبدِلها ببدائل عند الضرورة.
في بعض الحالات، إذا كان تطبيقك يستخدم PAGE_SIZE كقيمة ملائمة غير مرتبطة بحجم الصفحة الأساسي، لن يؤدي ذلك إلى تعطُّل تطبيقك عند استخدامه في وضع 16 كيلوبايت. ومع ذلك، إذا تم تمرير هذه القيمة إلى النواة باستخدام
mmap بدون MAP_FIXED، ستظل النواة تستخدم صفحة كاملة، ما يؤدي إلى إهدار
بعض الذاكرة. لهذه الأسباب، تكون قيمة PAGE_SIZE غير محدّدة عند تفعيل وضع 16 كيلوبايت في NDK r27 والإصدارات الأحدث.
إذا كان تطبيقك يستخدم PAGE_SIZE بهذه الطريقة ولا يمرّر هذه القيمة مباشرةً إلى النواة، يمكنك إنشاء متغيّر جديد باسم جديد بدلاً من استخدام PAGE_SIZE للإشارة إلى أنّه يُستخدم لأغراض أخرى ولا يشير إلى صفحة ذاكرة حقيقية.
تحسين أدوات تخصيص الذاكرة المخصّصة
في أنظمة 16 كيلوبايت، تكون أصغر وحدة من الذاكرة الفعلية التي يخصّصها نظام التشغيل أكبر بأربع مرات من تلك الموجودة في أنظمة 4 كيلوبايت. إذا تم تصميم أداة تخصيص مخصّصة استنادًا إلى افتراضات 4 كيلوبايت، يمكنها توزيع عناصر صغيرة على عدة صفحات بحجم 16 كيلوبايت والاحتفاظ بالذاكرة الفارغة بدون داعٍ. ويمكن أن يؤدي ذلك إلى زيادة كبيرة في استخدام الذاكرة الفعلية (RSS) وتقليل كفاءة مساحة الإبدال المضغوطة (ZRAM).
إذا كانت التعليمات البرمجية تدير مجموعات الذاكرة الخاصة بها، اتّبِع الاقتراحات التالية:
1. تجنُّب الحدود الدنيا الثابتة لعدد وحدات البايت من أجل تحرير الذاكرة
يستخدم العديد من أدوات التخصيص حدودًا ثابتة لعدد البايتات لتحديد وقت إعادة الذاكرة إلى نظام التشغيل باستخدام madvise(MADV_DONTNEED) (على سبيل المثال، لا تتم إعادة الذاكرة إلا إذا كانت العناصر النشطة تشغل أقل من 8 كيلوبايت).
في نظام 16 كيلوبايت، يؤدي حتى كائن نشط واحد بحجم 16 بايت إلى تثبيت صفحة كاملة بحجم 16 كيلوبايت (وهو أكبر من 8 كيلوبايت). ونتيجةً لذلك، لا يتم استيفاء الحد الأدنى المطلوب للإصدار، ولا يعيد أداة التخصيص مطلقًا الذاكرة المحيطة غير المستخدَمة إلى النواة.
ما يجب فعله: لا تستخدِم مطلقًا ثوابت البايت المضمّنة في التعليمات البرمجية لإحصاءات إصدار الصفحة.
تغيير حدود الإصدار ديناميكيًا في وقت التشغيل استنادًا إلى حجم الصفحة الفعلي
باستخدام sysconf(_SC_PAGESIZE)
2. ملء الصفحات المستخدَمة أولاً (التخصيص الكثيف أولاً)
إذا كان برنامج التخصيص يوزّع الذاكرة بترتيب الأولوية أو التوزيع الدوري، سيتم توزيع عمليات التخصيص الجديدة على العديد من الصفحات التي تبلغ سعتها 16 كيلوبايت والمملوءة جزئيًا. يحتفظ عنصر واحد على الصفحة بجميع وحدات 16 كيلوبايت المقيمة في ذاكرة الوصول العشوائي الفعلية.
ما يجب فعله: احرص دائمًا على تخصيص عناصر جديدة من الصفحة أو اللوح الأكثر امتلاءً (الأكثر كثافة) قبل الانتقال إلى الصفحات الفارغة أو التي يتم استخدامها بشكل خفيف. يسمح تركيز عمليات التخصيص الجديدة على الصفحات التي تم تعديلها بالفعل بأن يتم إفراغ الصفحات التي يتم استخدامها بشكل خفيف من الكائنات النشطة بشكل طبيعي، وبالتالي يمكن إتاحة الصفحة الكاملة التي تبلغ سعتها 16 كيلوبايت لنظام التشغيل.
3- محاذاة مجموعات الذاكرة إلى 16 كيلوبايت والحفاظ على أحجام المجموعات معتدلة
يمكن أن تحتوي النطاقات المتعددة الصفحات المصمَّمة لأنظمة 4 كيلوبايت على مساحة ذاكرة غير مستخدَمة بشكل مفرط في أنظمة التشغيل 16 كيلوبايت. بالإضافة إلى ذلك، تؤدي فئات الحجم التي لا يمكن تقسيمها بالتساوي إلى 16 كيلوبايت إلى حدوث تجزئة في نهاية كل صفحة.
ما يجب فعله:
- تأكَّد من أنّ جميع مجموعات الذاكرة وحدود الألواح وعمليات محاذاة المخزن المؤقت هي مضاعفات دقيقة لحجم الصفحة في وقت التشغيل.
- أعِد تقييم أحجام النطاقات المتعدّدة الصفحات لفئات العناصر الصغيرة لتجنُّب تخصيص شرائح كبيرة جدًا تحجز الذاكرة غير النشطة.
4. إخلاء الذاكرة الفعلية للمخازن المؤقتة الكبيرة المخزّنة مؤقتًا على الفور
تخزّن أدوات التخصيص عادةً مخازن مؤقتة كبيرة الحجم (أكبر من 64 كيلوبايت) في مجموعة داخل الذاكرة، ما يتيح إعادة استخدامها بدون تكبُّد النفقات العامة لاستدعاءات النظام mmap أو munmap. ومع ذلك، يؤدي الاحتفاظ بهذه المخازن المؤقتة غير النظيفة في الذاكرة إلى إهدار ميغابايت من ذاكرة الوصول العشوائي الفعلية أثناء انتظار مؤقت الإخلاء.
الإجراء المطلوب: احتفظ بنطاق عناوين الذاكرة الافتراضية محجوزًا لإعادة الاستخدام السريع،
ولكن استدعِ madvise(..., MADV_DONTNEED) أو madvise(..., MADV_FREE) على الفور
عند إعادة المخزن المؤقت إلى ذاكرة التخزين المؤقت. يسترد نظام التشغيل ذاكرة الوصول العشوائي (RAM) الفعلية على الفور، بينما يمكن لتطبيقك إعادة استخدام العنوان الظاهري على الفور بدون إعادة التخصيص.
5. تصفير الذاكرة عند التحرير بدلاً من التخصيص لضغط ZRAM
يستخدم نظام التشغيل Android مساحة تبديل مضغوطة (ZRAM) لإبقاء التطبيقات التي تعمل في الخلفية في الذاكرة. على الأجهزة التي تبلغ سعة ذاكرتها 16 كيلوبايت، إذا كانت الصفحة تتضمّن عنصرًا واحدًا مباشرًا على الأقل، ستبقى الصفحة بأكملها التي تبلغ سعتها 16 كيلوبايت مقيمة أو سيتم نقلها إلى ZRAM. تؤدي البيانات غير المرغوب فيها المتبقية (مثل المؤشرات والسلاسل القديمة) في الأجزاء التي تم تحريرها سابقًا من تلك الصفحة إلى انخفاض مستوى الضغط.
إذا كان برنامج التخصيص يضبط الذاكرة على صفر (مثل الأمان أو عمليات التخصيص التي تم ضبطها على صفر)، ننصحك بضبطها على صفر عند إلغاء التخصيص (free()) بدلاً من ضبطها على صفر عند التخصيص:
- تكلفة الصفحات المثبّتة أقل: يتم ضغط الذاكرة غير النشطة على صفحات 16 كيلوبايت المعبأة جزئيًا إلى حجم صغير جدًا في ZRAM، وبالتالي لا تستهلك الصفحات المثبّتة مساحة تبديل فعلية.
- الحد الأدنى من الحمل الزائد للتخزين المؤقت: عند استدعاء
free()، تكون الذاكرة مخزّنة مؤقتًا في ذاكرة التخزين المؤقت لوحدة المعالجة المركزية، ما يمنع حدوث المزيد من أخطاء التخزين المؤقت لاحقًا.
ملخّص الاقتراحات
| المنطقة | الاقتراح | التأثير المتوقّع |
|---|---|---|
| حدود الحذف | يمكنك تعديل حدود الإصدار بشكلٍ ديناميكي باستخدام sysconf(_SC_PAGESIZE). |
يمنع منطق الإصدار من حدوث توقّف تام بشكل دائم. |
| ترتيب التخصيص | يجب تخصيص المساحة من الصفحة أو الجزء الأكثر كثافة (الممتلئ تقريبًا) أولاً. | يقلّل من حجم الذاكرة المقيمة (RSS) من خلال تجميع العناصر النشطة معًا. |
| تحديد حجم الامتداد | يجب أن تتوافق فئات الحجم مع مضاعفات 16 كيلوبايت وتجنُّب الشرائح الكبيرة جدًا. | يزيل تجزئة الصفحة الأخيرة ويقلّل من مساحة الذاكرة غير المستخدَمة. |
| ذاكرات التخزين المؤقت | استدعِ الدالة madvise(MADV_DONTNEED) فورًا عند تخزين المخازن المؤقتة الكبيرة. |
تزيل هذه الميزة تضخّم ذاكرة الوصول العشوائي غير النشطة مع الحفاظ على سرعة إعادة الاستخدام الافتراضي. |
| مساحة التبديل / ZRAM | تصفير الذاكرة عند free() بدلاً من تصفيرها عند التخصيص |
تحسين نسب ضغط ZRAM لتقليل تكلفة الصفحات المثبّتة |
التحقّق من توافق حِزم تطوير البرامج (SDK) مع صفحة الذاكرة بحجم 16 كيلوبايت
تتوافق العديد من حِزم تطوير البرامج (SDK) مع أحجام الصفحات البالغة 16 كيلوبايت، خاصةً إذا أنشأتها بنفسك أو حصلت على إصدارات مسبقة الإنشاء حديثة. ومع ذلك، بما أنّ بعض حِزم SDK المجمَّعة مسبقًا أو إصدارات حِزم SDK غير متوافقة مع حجم 16 كيلوبايت، عليك مراجعة الموقع الإلكتروني لكل موفّر حزمة SDK لتحديد الإصدار الذي يجب استخدامه مع حجم 16 كيلوبايت.
اختبار تطبيقك في بيئة تتضمّن صفحات ذاكرة بحجم 16 كيلوبايت
بعد إنشاء تطبيقك مع توفير إمكانية استخدامه على الأجهزة التي تبلغ سعة صفحات الذاكرة فيها 16 كيلوبايت، عليك اختباره في بيئة تتضمن صفحات ذاكرة بحجم 16 كيلوبايت لمعرفة ما إذا كان تطبيقك سيواجه أي مشاكل. لإجراء هذا، اتبع هذه الخطوات:
إعداد حزمة تطوير البرامج (SDK) لنظام التشغيل Android 15 أو إصدار أحدث
إعداد إحدى بيئات الاختبار التالية:
- إعداد Android Emulator باستخدام صورة نظام تستند إلى 16 كيلوبايت وتعمل بالإصدار Android 15
- استخدام Cuttlefish مع حجم الصفحة 16 كيلوبايت على ARM64
- محاكاة Cuttlefish مع حجم صفحة يبلغ 16 كيلوبايت على x86-64
- تفعيل الوضع 16 كيلوبايت على جهاز باستخدام خيارات المطوّرين
- استخدام "مختبر الاختبار عن بُعد" من Samsung على الأجهزة المتوافقة مع الصفحات بحجم 16 كيلوبايت
ابدأ تشغيل جهازك الاختباري، ثم نفِّذ الأمر التالي للتأكّد من أنّه يستخدم بيئة تتضمّن صفحات ذاكرة بحجم 16 كيلوبايت:
adb shell getconf PAGE_SIZEيجب أن يعرض الأمر القيمة
16384.نفِّذ الأمر
zipalignالتالي للتأكّد من أنّ تطبيقك متوافق مع حجم 16 كيلوبايت، حيث يمثّل APK_NAME اسم ملف APK الخاص بتطبيقك:zipalign -c -P 16 -v 4 APK_NAME.apkاختبِر تطبيقك بدقة، مع التركيز على أي مناطق قد تتأثر بتغيير مثيلات الرموز التي تشير إلى أحجام صفحات معيّنة.
إعداد Android Emulator باستخدام صورة نظام تستند إلى 16 كيلوبايت
لإعداد بيئة تتضمّن صفحات بحجم 16 كيلوبايت باستخدام Android Emulator، اتّبِع الخطوات التالية:
- في "استوديو Android"، انقر على الأدوات > SDK Manager.
في علامة التبويب منصات حزمة SDK، انقر على عرض تفاصيل الحزمة، ثم وسِّع قسم Android VanillaIceCream أو إصدار أحدث، واختَر صورة نظام محاكي واحدة أو كلتيهما، وذلك حسب الأجهزة الافتراضية التي تريد إنشاءها:
- صورة نظام ARM 64 v8a بحجم صفحة تجريبية يبلغ 16 كيلوبايت لواجهات Google APIs
- Google APIs Experimental 16 KB Page Size Intel x86_64 Atom System Image
انقر على تطبيق > حسنًا لتنزيل صور النظام التي اخترتها.
اتّبِع الخطوات لإعداد جهاز افتراضي لنظام التشغيل Android 15، وعندما يُطلب منك اختيار صورة نظام، اختَر صورة النظام بحجم 16 كيلوبايت التي نزّلتها. إذا لم يتم اقتراحها تلقائيًا، يمكنك العثور على صورة النظام بحجم 16 كيلوبايت في علامة التبويب صور أخرى.
تشغيل المحاكي
بعد الانتهاء من إعداد "محاكي Android" والأجهزة الافتراضية، شغِّل المحاكي من قائمة الجهاز المستهدَف أو من سطر الأوامر.
تفعيل الوضع 16 كيلوبايت على جهاز باستخدام خيارات المطوّرين
فعِّل خيار المطوّر التشغيل مع صفحات حجمها 16 كيلوبايت لتشغيل الجهاز في وضع 16 كيلوبايت.
في إصدارات QPR من نظام التشغيل Android 15، يمكنك استخدام خيار المطوّرين المتاح على أجهزة معيّنة لإعادة تشغيل الجهاز في وضع 16 كيلوبايت وإجراء اختبار على الجهاز فقط. قبل استخدام خيار المطوّرين، انتقِل إلى الإعدادات > النظام > تحديثات البرامج وطبِّق أي تحديثات متوفّرة.
يتوفّر خيار المطوّرين هذا على الأجهزة التالية:
Pixel 8 وPixel 8 Pro (مع الإصدار 1 من حزمة إصلاح الأخطاء في نظام Android 15 أو إصدار أحدث)
Pixel 8a (مع الإصدار 1 من حزمة إصلاح الأخطاء في نظام Android 15 أو إصدار أحدث)
Pixel 9 و9 Pro و9 Pro XL (مع الإصدار الثاني من حزمة Android 15 QPR أو إصدار أحدث)
Pixel 9a (مع نظام التشغيل Android 16 أو إصدار أحدث)
وضع التوافق مع الإصدارات السابقة بحجم 16 كيلوبايت
تحذير في وضع التوافق مع حجم الصفحة
يتوفّر خيار التوافق مع الإصدارات السابقة بحجم 16 كيلوبايت عندما يعمل الجهاز بنواة بحجم 16 كيلوبايت. يدير مدير الحِزم تطبيقًا في وضع التوافق مع الإصدارات السابقة بحجم 16 كيلوبايت عند استيفاء الشروط التالية:
- إذا كان التطبيق يحتوي على ملفات ELF (بالامتداد
.so) مع محاذاة مقطع LOAD بحجم 4 كيلوبايت. - إذا كانت حزمة APK المضغوطة تحتوي على ملفات ELF غير مضغوطة بحجم 4 كيلوبايت ومحاذية لملف ZIP.
إذا فعّل مدير الحِزم وضع التوافق مع الإصدارات السابقة بحجم 16 كيلوبايت لأحد التطبيقات، سيعرض التطبيق تحذيرًا عند تشغيله للمرة الأولى يفيد بأنّه يعمل في وضع التوافق مع الإصدارات السابقة بحجم 16 كيلوبايت.
يتيح وضع التوافق مع الإصدارات القديمة الذي يبلغ حجم الصفحة فيه 16 كيلوبايت لبعض التطبيقات العمل، ولكن للحصول على أفضل موثوقية واستقرار، يجب أن تظل التطبيقات متوافقة مع حجم الصفحة البالغ 16 كيلوبايت.
في صفحة معلومات التطبيق، ضِمن الإعدادات المتقدّمة، فعِّل أو أوقِف الإعداد تشغيل التطبيق في وضع التوافق مع حجم الصفحة لتفعيل وضع التوافق مع الإصدارات السابقة بحجم 16 كيلوبايت أو إيقافه لتطبيق معيّن. يظهر هذا الإعداد فقط عندما يعمل الجهاز بحجم صفحة يبلغ 16 كيلوبايت.
إعداد وضع التوافق مع حجم الصفحة
لفرض التوافق مع الإصدارات القديمة بحجم 16 كيلوبايت لكل تطبيق على الجهاز، اتّبِع الخطوات التالية:
adb shell setprop bionic.linker.16kb.app_compat.enabled true
adb shell setprop pm.16kb.app_compat.disabled false
لإيقاف توافق 16 كيلوبايت مع الإصدارات القديمة لكل تطبيق على الجهاز، اتّبِع الخطوات التالية:
adb shell setprop bionic.linker.16kb.app_compat.enabled false
adb shell setprop pm.16kb.app_compat.disabled true
في نظام التشغيل Android 17، يمكنك أيضًا إيقاف التوافق مع الإصدارات القديمة بحجم 16 كيلوبايت لكل تطبيق، ما يؤدي إلى إيقاف أي ملف ثنائي غير متوافق على الفور:
adb shell setprop bionic.linker.16kb.app_compat.enabled fatal
adb shell setprop pm.16kb.app_compat.disabled true
اضبط السمة android:pageSizeCompat على "مفعَّل" أو "غير مفعَّل" لتفعيل وضع التوافق مع الإصدارات القديمة أو إيقافه لتطبيق معيّن في AndroidManifest.xml. عند ضبط هذه السمة، لن يعرض التطبيق تحذيرات بشأن وضع التوافق مع الإصدارات القديمة عند تشغيله.