ในอดีต Android รองรับเฉพาะหน้าหน่วยความจำขนาด 4 KB ซึ่งได้ เพิ่มประสิทธิภาพหน่วยความจำของระบบสำหรับปริมาณหน่วยความจำทั้งหมดโดยเฉลี่ยที่ อุปกรณ์ Android มักจะมี ตั้งแต่ Android 15 เป็นต้นไป AOSP จะรองรับ อุปกรณ์ที่กำหนดค่าให้ใช้หน้าขนาด 16 KB (อุปกรณ์ 16 KB) หากแอปใช้ไลบรารี NDK ไม่ว่าจะโดยตรงหรือโดยอ้อมผ่าน SDK คุณจะต้องสร้างแอปใหม่เพื่อให้ทำงานในอุปกรณ์ที่มีขนาด 16 KB เหล่านี้ได้
เนื่องจากผู้ผลิตอุปกรณ์ยังคงสร้างอุปกรณ์ที่มีหน่วยความจำจริง (RAM) มากขึ้น อุปกรณ์จำนวนมากเหล่านี้จะใช้ขนาดหน้า 16 KB (และในที่สุดก็จะใหญ่ขึ้น) เพื่อเพิ่มประสิทธิภาพของอุปกรณ์ การเพิ่มการรองรับอุปกรณ์ที่มีขนาดหน้า 16 KB จะช่วยให้แอปของคุณทำงานบนอุปกรณ์เหล่านี้ได้ และช่วยให้แอปได้รับประโยชน์จากการปรับปรุงประสิทธิภาพที่เกี่ยวข้อง หากไม่มีการคอมไพล์ใหม่ แอปจะใช้ไม่ได้ในอุปกรณ์แบบ 16 KB ใน Android รุ่นต่อๆ ไป
เราได้ให้คำแนะนำเกี่ยวกับวิธีตรวจสอบว่าแอปได้รับผลกระทบหรือไม่ วิธีสร้างแอปใหม่ (หากมี) และวิธีทดสอบแอปในสภาพแวดล้อมแบบ 16 KB โดยใช้โปรแกรมจำลอง (รวมถึงอิมเมจระบบ Android 15 สำหรับ Android Emulator) เพื่อช่วยให้คุณเพิ่มการรองรับแอปได้
ข้อกำหนดความเข้ากันได้ของ Google Play
แอปทั้งหมดที่กำหนดเป้าหมายเป็น Android 15 (ระดับ API 35) ขึ้นไปต้องรองรับหน้าหน่วยความจำขนาด 16 KB ในอุปกรณ์ 64 บิตบน Google Play เพื่อให้มั่นใจว่าแอปของคุณจะทำงานได้อย่างถูกต้องใน Android เวอร์ชันล่าสุด ตั้งแต่วันที่ 1 กุมภาพันธ์ 2027 เป็นต้นไป หากการอัปเดตแอปของคุณไม่รองรับหน้าหน่วยความจำขนาด 16 KB คุณจะเผยแพร่การอัปเดตเหล่านี้ไม่ได้
สิทธิประโยชน์และประสิทธิภาพที่เพิ่มขึ้น
อุปกรณ์ที่กำหนดค่าหน้าเว็บขนาด 16 KB จะใช้หน่วยความจำโดยเฉลี่ยมากกว่าเล็กน้อย แต่ปรับปรุงประสิทธิภาพการทำงานได้หลากหลายสำหรับทั้งระบบและแอป ดังนี้
- เวลาเปิดแอปลดลงขณะที่ระบบมีภาระเกี่ยวกับหน่วยความจำ: ลดลงโดยเฉลี่ย 3.16% โดยการปรับปรุงที่เห็นได้ชัดมากขึ้น (สูงสุด 30%) สำหรับบางแอปที่เราทดสอบ
- การลดพลังงานในระหว่างการเปิดแอป: ลดลง 4.56% โดยเฉลี่ย
- การเปิดตัวกล้องเร็วขึ้น: Hot Start เร็วขึ้น 4.48% โดยเฉลี่ย และ Cold Start เร็วขึ้น 6.60% โดยเฉลี่ย
- ปรับปรุงเวลาในการบูตระบบ: เร็วขึ้น 8% (ประมาณ 950 มิลลิวินาที) โดยเฉลี่ย
การปรับปรุงเหล่านี้อิงตามการทดสอบขั้นต้นของเรา และผลลัพธ์ในอุปกรณ์จริงอาจแตกต่างกัน เราจะให้การวิเคราะห์เพิ่มเติมเกี่ยวกับโอกาสในการได้ผู้ใช้ใหม่สำหรับแอปขณะที่เราทำการทดสอบต่อไป
ตรวจสอบว่าแอปของคุณได้รับผลกระทบหรือไม่
หากแอปใช้โค้ดเนทีฟ คุณควรสร้างแอปใหม่ ให้รองรับอุปกรณ์ขนาด 16 KB หากไม่แน่ใจว่าแอปใช้โค้ดเนทีฟหรือไม่ คุณสามารถใช้ APK Analyzer เพื่อระบุว่ามีโค้ดเนทีฟหรือไม่ จากนั้นตรวจสอบการจัดแนวของส่วน ELF สำหรับไลบรารีที่ใช้ร่วมกันที่คุณพบ Android Studio ยังมีฟีเจอร์ที่จะช่วยให้คุณตรวจหาปัญหาการจัดแนวโดยอัตโนมัติได้ด้วย
หากแอปใช้เฉพาะโค้ดที่เขียนในภาษาโปรแกรม Java หรือ Kotlin ซึ่งรวมถึงไลบรารีหรือ SDK ทั้งหมด แสดงว่าแอปของคุณรองรับอุปกรณ์ขนาด 16 KB อยู่แล้ว อย่างไรก็ตาม เราขอแนะนำให้คุณทดสอบแอปในสภาพแวดล้อมแบบ 16 KB เพื่อยืนยันว่าไม่มีการถดถอยที่ไม่คาดคิดในลักษณะการทำงานของแอป
แอปของคุณใช้โค้ดแบบเนทีฟหรือไม่
แอปของคุณใช้โค้ดแบบเนทีฟหากมีข้อใดต่อไปนี้
- แอปของคุณใช้โค้ด C/C++ (เนทีฟ) หากแอปใช้ Android NDK แสดงว่าแอปใช้โค้ดแบบเนทีฟ
- แอปของคุณลิงก์กับไลบรารีแบบเนทีฟหรือทรัพยากร Dependency ของบุคคลที่สาม (เช่น SDK) ที่ใช้ไลบรารีเหล่านั้น
- แอปของคุณสร้างขึ้นโดยเครื่องมือสร้างแอปของบุคคลที่สามซึ่งใช้ไลบรารีแบบเนทีฟในอุปกรณ์
ระบุไลบรารีแบบเนทีฟโดยใช้ตัววิเคราะห์ APK
ตัววิเคราะห์ APK เป็นเครื่องมือที่ช่วยให้คุณประเมินแง่มุมต่างๆ ของ APK ที่สร้างขึ้นได้ วิธีตรวจสอบว่าแอปของคุณใช้โค้ดแบบเนทีฟหรือไม่ (ไม่ว่าแอปจะรองรับขนาดหน้า 16 KB หรือไม่ก็ตาม)
- เปิด Android Studio แล้วคลิกไฟล์ > เปิด แล้วเลือกโปรเจ็กต์
จากแถบเมนู ให้คลิกสร้าง > วิเคราะห์ APK...
เลือก APK ที่ต้องการวิเคราะห์
มองหาในโฟลเดอร์
libซึ่งโฮสต์ไฟล์ออบเจ็กต์ที่แชร์ (.so) หากมี หากมีไฟล์ออบเจ็กต์ที่แชร์ แอปจะใช้โค้ดเนทีฟ คอลัมน์การจัดแนวจะแสดงข้อความเตือนสำหรับไฟล์ที่มีปัญหา เกี่ยวกับการจัดแนว หากไม่มีไฟล์ออบเจ็กต์ที่แชร์หรือไม่มีโฟลเดอร์libแสดงว่าแอปไม่ได้ใช้โค้ดแบบเนทีฟ
ตรวจหาปัญหาการจัดแนวด้วยการตรวจสอบอัตโนมัติ
Android Studio จะแจ้งเตือนคุณล่วงหน้าหากไลบรารีหรือ APK ที่สร้างไว้ล่วงหน้าไม่เป็นไปตามข้อกำหนด 16 KB ใช้เครื่องมือ APK Analyzer เพื่อตรวจสอบว่าต้องอัปเดตไลบรารีใด หรือต้องเปลี่ยนแปลงโค้ดหรือไม่
เครื่องมือวิเคราะห์ซอร์สโค้ดใน Android Studio ยังไฮไลต์ไลบรารีแบบเนทีฟที่ไม่ได้จัดเรียงตามรูปแบบความจำขนาด 16 KB ด้วย
ตรวจสอบการจัดแนวของกลุ่ม ELF สำหรับไลบรารีที่ใช้ร่วมกัน
สำหรับไลบรารีที่ใช้ร่วมกัน ให้ตรวจสอบว่ากลุ่ม ELF ของไลบรารีที่ใช้ร่วมกัน
ได้รับการจัดแนวอย่างถูกต้องโดยใช้การจัดแนว ELF ขนาด 16 KB หากคุณพัฒนาบน 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_64ใดUNALIGNEDคุณจะต้องอัปเดตการแพ็กเกจสำหรับไลบรารีเหล่านั้น จากนั้นคอมไพล์แอปอีกครั้งและทดสอบอีกครั้งโดยทำตามขั้นตอนในส่วนนี้
ใช้เครื่องมือบรรทัดคำสั่งโดยตรง
ทำตามขั้นตอนต่อไปนี้เพื่อตรวจสอบการจัดแนวของกลุ่ม ELF โดยใช้เครื่องมือบรรทัดคำสั่งโดยตรง
- ตรวจสอบว่าได้ติดตั้งทั้งเครื่องมือสร้าง Android SDK เวอร์ชัน 35.0.0 ขึ้นไปและ 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 SDKSHARED_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.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 SDK และAPK_NAMEคือชื่อไฟล์ APK ของแอป บรรทัดสุดท้ายของเอาต์พุตจะระบุว่า "การยืนยันสำเร็จ" หาก ไลบรารีที่แชร์ทั้งหมดสอดคล้องกันอย่างถูกต้องหากการยืนยันล้มเหลว คุณจะต้องปรับไลบรารีที่แชร์บางรายการใหม่ ดังนั้นคุณจะต้องอัปเดตการแพ็กเกจสำหรับไลบรารีเหล่านั้น จากนั้นคอมไพล์แอปอีกครั้งและทดสอบอีกครั้งโดยทำตามขั้นตอนในส่วนนี้
ตรวจสอบแฟล็กความปลอดภัย RELRO
Linker สมัยใหม่ใช้แฟล็ก การเปลี่ยนเส้นทางแบบอ่านอย่างเดียว (RELRO) เพื่อทำให้ส่วนการเปลี่ยนเส้นทาง ของไฟล์ออบเจ็กต์ที่แชร์เป็นแบบอ่านอย่างเดียวหลังจากโหลด เพื่อลดการใช้ช่องโหว่ด้านความปลอดภัย เปิดใช้ Flag RELRO ในบิลด์
ส่วน RELRO ที่มีที่อยู่เริ่มต้นและขนาดกลุ่ม (MemSize) ที่ไม่ได้
จัดแนว 16 KB จะทําให้แอปขัดข้องขณะรันไทม์เนื่องจากข้อผิดพลาดในการแบ่งส่วน ปัญหานี้จะเกิดขึ้นหากสร้างไฟล์ .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'
ระบบจะพิมพ์สตริง GNU_RELRO หากมีกลุ่ม RELRO
จากนั้นตรวจสอบการจัดเรียงกลุ่ม RELRO โดยการรวมที่อยู่ชดเชยเสมือน (VirtAddr) กับ ขนาดหน่วยความจำของกลุ่ม (MemSiz) และหารด้วย 16 KB (0x4000) หาก เศษ (โมดูโล) เป็น 0 แสดงว่ากลุ่ม RELRO มีการจัดแนว 16 KB
ต่อไปนี้คือตัวอย่างไฟล์ .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 ไม่ใช่ 0 ดังนั้น libbad.so จึงไม่เป็นไปตามข้อกำหนด 16 KB ช่วงการป้องกัน RELRO ตั้งแต่ DC000 (ตัวแบ่งหน้าก่อนหน้า) ถึง E4000 เป็นแบบอ่านอย่างเดียว แต่ Android Linker คาดหวังให้ช่วงย่อยตั้งแต่ E1000 ถึง E4000 เป็นแบบ เขียนได้ ซึ่งส่งผลให้เกิดข้อผิดพลาดในการแบ่งส่วน ในกรณีนี้ ให้สร้างไฟล์ .so อีกครั้งตามที่อธิบายไว้ในส่วนคอมไพล์แอปโดยใช้การจัดแนว ELF ขนาด 16 KB
ตัวอย่างไฟล์ .so ที่จัดแนวพร้อมส่วน RELRO มีดังนี้
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
GNU_RELRO 0x0cfaf0 0x00000000000dfaf0 0x00000000000dfaf0 0x01510 0x00510 R 0x1
สร้างแอปให้รองรับอุปกรณ์ที่ใช้หน้าหน่วยความจำขนาด 16 KB
หากแอปใช้โค้ดแบบเนทีฟ ให้ทำตามขั้นตอนที่ระบุไว้ในส่วนต่อไปนี้เพื่อให้แน่ใจว่าแอปของคุณรองรับอุปกรณ์ 16 KB
- อัปเดตการแพ็กเกจไลบรารีที่ใช้ร่วมกัน
- คอมไพล์แอปโดยใช้การจัดวาง ELF ขนาด 16 KB
- แก้ไขโค้ดและปัญหาที่เกิดขึ้นขณะรันไทม์
- เพิ่มประสิทธิภาพเครื่องมือจัดสรรหน่วยความจำที่กำหนดเอง (หากมี)
- ตรวจสอบว่า SDK รองรับขนาด 16 KB หรือไม่
อัปเดตการแพ็กเกจไลบรารีที่ใช้ร่วมกัน
อัปเกรดเป็น AGP เวอร์ชัน 8.5.1 ขึ้นไป และใช้ไลบรารีที่ใช้ร่วมกันที่ไม่ได้บีบอัด
ใช้ bundletool เพื่อยืนยันการจัดแนวซิป
หากต้องการดูการจัดแนวของแพ็กเกจ ให้ใช้
bundletool dump config --bundle=<my .aab> | grep alignment
หากเห็น PAGE_ALIGNMENT_16K แสดงว่าคำขอชุดของคุณมีการจัดแนว ZIP ขนาด 16 KB
หากเห็น PAGE_ALIGNMENT_4K แสดงว่า APK ที่สร้างจาก
AAB นี้จะมีไฟล์ .so ที่จัดแนว 4 KB ในไฟล์ ZIP
AGP เวอร์ชัน 8.5.1 ขึ้นไป
อุปกรณ์ขนาด 16 KB กำหนดให้แอปที่จัดส่งพร้อมไลบรารีที่ใช้ร่วมกันที่ไม่ได้บีบอัดต้อง จัดวางไลบรารีเหล่านั้นในขอบเขตที่จัดวางด้วย zip ขนาด 16 KB โดยคุณต้องอัปเกรด เป็นปลั๊กอิน Android Gradle (AGP) เวอร์ชัน 8.5.1 ขึ้นไป ดูรายละเอียดเกี่ยวกับกระบวนการอัปเกรดได้ที่ส่วนผู้ช่วยอัปเกรดปลั๊กอิน Android Gradle
AGP เวอร์ชัน 8.5 หรือต่ำกว่า
หากอัปเกรด AGP เป็นเวอร์ชัน 8.5.1 ขึ้นไปไม่ได้ คุณสามารถ เปลี่ยนไปใช้ไลบรารีที่ใช้ร่วมกันที่บีบอัดแทนได้ อัปเดตการกำหนดค่า Gradle เพื่อให้ Gradle บีบอัดไลบรารีที่แชร์เมื่อแพ็กเกจแอปเพื่อหลีกเลี่ยงปัญหาการติดตั้งแอปที่มีไลบรารีที่แชร์ซึ่งไม่ได้จัดวาง
ดึงดูด
เพิ่มตัวเลือกต่อไปนี้ในไฟล์ build.gradle
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging true
}
}
}
Kotlin
เพิ่มตัวเลือกต่อไปนี้ในไฟล์ build.gradle.kts
android {
...
packagingOptions {
jniLibs {
useLegacyPackaging = true
}
}
}
AGP เวอร์ชัน 8.0 หรือต่ำกว่า
หากใช้ AGP เวอร์ชัน 8.0 หรือต่ำกว่า คุณจะต้องปิดใช้ตัวเลือกไลบรารีแบบเนทีฟที่ไม่ได้บีบอัดสำหรับ App Bundle ในไฟล์ gradle.properties ด้วย
android.bundle.enableUncompressedNativeLibs=false
คอมไพล์แอปโดยใช้การจัดวาง ELF ขนาด 16 KB
อุปกรณ์ขนาด 16 KB กำหนดให้ต้องจัดวางส่วน ELF ของไลบรารีที่ใช้ร่วมกันอย่างถูกต้องโดยใช้การจัดวาง ELF ขนาด 16 KB เพื่อให้แอปทำงานได้
สำหรับนักพัฒนาเกม หากเกมของคุณทำงานบนเกมเอนจิน Unity โปรดดูคู่มือ Unity หากเกมของคุณทำงานบนเกมเอนจิน Unreal โปรดดูคำแนะนำสำหรับ Unreal สำหรับเกมเอนจินเนทีฟ ให้ทำตามคำแนะนำนี้ต่อไป
หากต้องการคอมไพล์แอปโดยใช้การจัดแนว ELF ขนาด 16 KB ให้ทำตามขั้นตอนในส่วนใดส่วนหนึ่งต่อไปนี้ ทั้งนี้ขึ้นอยู่กับเวอร์ชันของ Android NDK ที่คุณใช้
Android NDK r28 ขึ้นไป
NDK เวอร์ชัน r28 ขึ้นไปจะคอมไพล์การจัดแนว 16 KB โดยค่าเริ่มต้น
Android NDK r27 และต่ำกว่า
หากต้องการรองรับการคอมไพล์ไลบรารีที่ใช้ร่วมกันซึ่งจัดแนว 16 KB ด้วย Android NDK เวอร์ชัน r27 หรือต่ำกว่า ให้ใช้แฟล็กของลิงเกอร์ต่อไปนี้
-Wl,-z,max-page-size=16384
-Wl,-z,common-page-size=16384
วิธีอัปเดตไฟล์การกำหนดค่าระบบบิลด์มีดังนี้
ndk-build
หากคุณใช้ ndk-build ให้อัปเดต Android.mk เพื่อเปิดใช้การจัดแนว ELF ขนาด 16 KB
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384 -Wl,-z,common-page-size=16384
CMake
หากคุณใช้ CMake ให้อัปเดต CMakeLists.txt เพื่อเปิดใช้การจัดแนว ELF ขนาด 16 KB
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
"-Wl,-z,max-page-size=16384"
"-Wl,-z,common-page-size=16384"
)
แก้ไขโค้ดและแก้ปัญหาที่เกิดขึ้นขณะรันไทม์
แม้ว่าแอปจะได้รับการจัดแนว 16 KB แล้ว แต่แอปก็อาจพบข้อผิดพลาดหากตำแหน่ง ในโค้ดของคุณคาดว่าอุปกรณ์ใช้ขนาดหน้าเว็บที่เฉพาะเจาะจง หากต้องการหลีกเลี่ยงปัญหานี้ ให้ทำตามขั้นตอนต่อไปนี้
นำการอ้างอิงที่ฮาร์ดโค้ดซึ่งอ้างอิงค่าคงที่
PAGE_SIZEหรืออินสแตนซ์ในตรรกะของโค้ดที่ถือว่าขนาดหน้าของอุปกรณ์ คือ 4 KB (4096) ออกโปรดใช้
getpagesize()หรือsysconf(_SC_PAGESIZE)แทนมองหาการใช้งาน
mmap()และ API อื่นๆ ที่ต้องมีอาร์กิวเมนต์ที่สอดคล้องกับหน้าเว็บ และแทนที่ด้วยทางเลือกอื่นหากจำเป็น
ในบางกรณี หากแอปของคุณใช้ PAGE_SIZE เป็นค่าที่สะดวกซึ่งไม่ได้
เชื่อมโยงกับขนาดหน้าหน่วยความจำพื้นฐาน การดำเนินการนี้จะไม่ทำให้แอปของคุณหยุดทำงานเมื่อ
ใช้ในโหมด 16 KB อย่างไรก็ตาม หากส่งค่านี้ไปยังเคอร์เนลด้วย
mmap โดยไม่มี MAP_FIXED เคอร์เนลจะยังคงใช้ทั้งหน้า ซึ่งทำให้สิ้นเปลือง
หน่วยความจำบางส่วน ด้วยเหตุนี้ PAGE_SIZE จึงไม่กำหนดเมื่อเปิดใช้โหมด 16 KB ใน NDK r27 ขึ้นไป
หากแอปของคุณใช้ PAGE_SIZE ในลักษณะนี้และไม่เคยส่งค่านี้ไปยังเคอร์เนลโดยตรง ให้สร้างตัวแปรใหม่ที่มีชื่อใหม่แทนการใช้ PAGE_SIZE เพื่อแสดงให้เห็นว่าใช้เพื่อวัตถุประสงค์อื่นและไม่ได้แสดงหน้าหน่วยความจำจริง
เพิ่มประสิทธิภาพตัวจัดสรรหน่วยความจำที่กำหนดเอง
ในระบบ 16 KB หน่วยความจำจริงที่เล็กที่สุดที่ระบบปฏิบัติการ จัดสรรจะมีขนาดใหญ่กว่าในระบบ 4 KB ถึง 4 เท่า หากออกแบบตัวจัดสรรที่กำหนดเองโดยอิงตามสมมติฐาน 4 KB ก็จะกระจายออบเจ็กต์ขนาดเล็กในหน้า 16 KB หลายหน้าและเก็บหน่วยความจำที่ว่างไว้โดยไม่จำเป็น ซึ่งอาจเพิ่มการใช้งานหน่วยความจำจริง (RSS) อย่างมากและลดประสิทธิภาพของ Swap ที่บีบอัด (ZRAM)
หากโค้ดจัดการพูลหน่วยความจำของตัวเอง ให้ทำตามคำแนะนำต่อไปนี้
1. หลีกเลี่ยงการกำหนดค่าขีดจำกัดไบต์แบบฮาร์ดโค้ดเพื่อเพิ่มพื้นที่ว่างในหน่วยความจำ
ผู้จัดสรรจำนวนมากใช้ขีดจำกัดไบต์คงที่เพื่อตัดสินใจว่าจะปล่อยหน่วยความจำกลับไปยัง
ระบบปฏิบัติการเมื่อใดโดยใช้ madvise(MADV_DONTNEED) (เช่น ปล่อยหน่วยความจำก็ต่อเมื่อ
ออบเจ็กต์ที่ใช้งานอยู่ใช้พื้นที่น้อยกว่า 8 KB)
ในระบบ 16 KB แม้แต่ออบเจ็กต์ที่ใช้งานจริงขนาด 16 ไบต์รายการเดียวก็ตรึงทั้งหน้าขนาด 16 KB (ซึ่งใหญ่กว่า 8 KB) ด้วยเหตุนี้ จึงไม่เคยถึงเกณฑ์การเผยแพร่ และตัวจัดสรรจึงไม่เคยคืนหน่วยความจำที่ไม่ได้ใช้โดยรอบ ให้กับเคอร์เนล
สิ่งที่ต้องทำ: อย่าใช้ค่าคงที่ไบต์ที่ฮาร์ดโค้ดสำหรับฮิวริสติกการเผยแพร่หน้าเว็บ
ปรับเกณฑ์การเผยแพร่แบบไดนามิกที่รันไทม์ตามขนาดหน้าเว็บจริง
โดยใช้ sysconf(_SC_PAGESIZE)
2. กรอกข้อมูลในหน้าที่ใช้แล้วก่อน (การจัดสรรแบบหนาแน่นก่อน)
หากตัวจัดสรรส่งหน่วยความจำตามลำดับแบบเข้าก่อนออกก่อน (FIFO) หรือแบบวนรอบ การจัดสรรใหม่จะกระจายไปทั่วหน้าขนาด 16 KB ที่เติมบางส่วนจำนวนมาก ออบเจ็กต์เดียวในหน้าเว็บจะเก็บข้อมูลทั้งหมด 16 KB ไว้ใน RAM จริง
สิ่งที่ต้องทำ: จัดสรรออบเจ็กต์ใหม่จากหน้าเว็บหรือสแล็บที่เต็มที่สุด (หนาแน่นที่สุด) เสมอ ก่อนที่จะแตะหน้าเว็บที่ว่างเปล่าหรือมีการใช้งานเล็กน้อย การมุ่งเน้นการจัดสรรใหม่ ในหน้าที่มีการเปลี่ยนแปลงอยู่แล้วจะช่วยให้หน้าที่มีการใช้งานน้อยค่อยๆ ลดจำนวนออบเจ็กต์ที่ใช้งานอยู่จนเหลือ 0 ดังนั้นระบบปฏิบัติการจึงสามารถปล่อยหน้าขนาด 16 KB ทั้งหมดได้
3. จัดแนวพูลหน่วยความจำเป็น 16 KB และรักษาระดับขนาดพูลให้ปานกลาง
ช่วงหลายหน้าเว็บที่ออกแบบมาสำหรับระบบ 4 KB อาจมีหน่วยความจำที่ยังไม่ได้เผยแพร่มากเกินไปในเคอร์เนล 16 KB นอกจากนี้ คลาสขนาดที่หารด้วย 16 KB ไม่ลงตัวจะทำให้เกิดการกระจายข้อมูลที่ส่วนท้ายของแต่ละหน้า
สิ่งที่ต้องทำ
- ตรวจสอบว่าพูลหน่วยความจำ ขอบเขตสแล็บ และการจัดแนวบัฟเฟอร์ทั้งหมดเป็น หลายเท่าของขนาดหน้าเว็บรันไทม์
- ประเมินขนาด Span หลายหน้าสำหรับคลาสออบเจ็กต์ขนาดเล็กอีกครั้งเพื่อหลีกเลี่ยงการจัดสรร Slab ที่ใหญ่เกินไปซึ่งจะดักหน่วยความจำที่ไม่มีการใช้งาน
4. ปล่อยหน่วยความจำจริงสำหรับบัฟเฟอร์ขนาดใหญ่ที่แคชไว้ทันที
โดยทั่วไปแล้ว ตัวจัดสรรที่กำหนดเองจะแคชบัฟเฟอร์ขนาดใหญ่ (> 64 KB) ในพูลในหน่วยความจำ
เพื่อให้สามารถนำกลับมาใช้ใหม่ได้โดยไม่ต้องเสียค่าใช้จ่ายเพิ่มเติมของmmapหรือmunmapระบบ
อย่างไรก็ตาม การเก็บบัฟเฟอร์ที่มีการแก้ไขเหล่านี้ไว้ในหน่วยความจำจะทำให้เสีย RAM จริงไปหลายเมกะไบต์ขณะรอตัวจับเวลาการนำออก
สิ่งที่ต้องทำ: จองช่วงที่อยู่หน่วยความจำเสมือนไว้เพื่อนำกลับมาใช้ใหม่ได้อย่างรวดเร็ว
แต่ให้เรียกใช้ madvise(..., MADV_DONTNEED) หรือ madvise(..., MADV_FREE) ทันที
เมื่อส่งคืนบัฟเฟอร์ไปยังแคช ระบบปฏิบัติการจะเรียกคืน RAM จริงทันที ในขณะที่แอปยังคงใช้ที่อยู่เสมือนซ้ำได้ทันทีโดยไม่ต้องจัดสรรใหม่
5. ล้างหน่วยความจำในพื้นที่ว่างแทนที่จะล้างเมื่อจัดสรรสำหรับการบีบอัด ZRAM
Android ใช้ Swap ที่บีบอัด (ZRAM) เพื่อเก็บแอปที่ทำงานอยู่เบื้องหลังไว้ในหน่วยความจำ ในอุปกรณ์ขนาด 16 KB หากหน้าเว็บมีออบเจ็กต์ที่ใช้งานอยู่แม้เพียง 1 รายการ หน้าเว็บขนาด 16 KB ทั้งหมดจะยังคงอยู่ในหน่วยความจำหรือสลับไปใช้ ZRAM ข้อมูลขยะที่เหลืออยู่ (เช่น Pointer และสตริงที่ไม่มีอัปเดต) ในส่วนของหน้าเว็บที่ก่อนหน้านี้ถูกปล่อย จะบีบอัดได้ไม่ดี
หากตัวจัดสรรของคุณตั้งค่าหน่วยความจำเป็น 0 (เช่น เพื่อความปลอดภัยหรือการจัดสรรที่เริ่มต้นด้วย 0) ให้พิจารณาตั้งค่าเป็น 0 เมื่อยกเลิกการจัดสรร (free()) แทนที่จะตั้งค่าเมื่อจัดสรร
- หน้าที่ปักหมุดมีค่าใช้จ่ายน้อยกว่า: หน่วยความจำที่ไม่ได้ใช้งานในหน้าขนาด 16 KB ที่เติมข้อมูลบางส่วนจะถูกบีบอัดใน ZRAM จนแทบไม่มีการใช้งาน ดังนั้นหน้าที่ปักหมุดจึงไม่สิ้นเปลืองพื้นที่สวอปจริง
- ค่าใช้จ่ายของแคชน้อยที่สุด: เมื่อมีการเรียกใช้
free()หน่วยความจำจะอยู่ในแคช CPU อยู่แล้ว ซึ่งจะช่วยหลีกเลี่ยงการไม่พบแคชเพิ่มเติมในภายหลัง
สรุปคำแนะนำ
| พื้นที่ | คำแนะนำ | ผลกระทบที่คาดหวัง |
|---|---|---|
| เกณฑ์การลบถาวร | ปรับเกณฑ์การเผยแพร่แบบไดนามิกโดยใช้ sysconf(_SC_PAGESIZE) |
ป้องกันไม่ให้ตรรกะการเผยแพร่หยุดชะงักอย่างถาวร |
| ลำดับการจัดสรร | จัดสรรจากหน้าหรือสแล็บที่มีความหนาแน่นมากที่สุด (เกือบเต็ม) ก่อน | ลดหน่วยความจำที่ใช้งาน (RSS) โดยการรวมออบเจ็กต์ที่ใช้งานอยู่ไว้ด้วยกัน |
| การกำหนดขนาดช่วง | จัดแนวคลาสขนาดให้เป็นทวีคูณของ 16 KB และหลีกเลี่ยง Slab ที่มีขนาดใหญ่เกินไป | ขจัดปัญหาการกระจายตัวของส่วนท้ายของหน้าและลดการใช้หน่วยความจำ |
| แคชบัฟเฟอร์ | เรียกใช้ madvise(MADV_DONTNEED) ทันทีเมื่อแคชบัฟเฟอร์ขนาดใหญ่ |
ลดการใช้ RAM ที่ไม่ได้ใช้งานมากเกินไปในขณะที่ยังคงการนำเสมือนกลับมาใช้ใหม่ได้อย่างรวดเร็ว |
| Swap / ZRAM | ล้างหน่วยความจำใน free() แทนที่จะล้างเมื่อจัดสรร |
ปรับปรุงอัตราส่วนการบีบอัด ZRAM เพื่อให้หน้าเว็บที่ปักหมุดมีค่าใช้จ่ายน้อยลง |
ตรวจสอบว่า SDK รองรับขนาด 16 KB หรือไม่
SDK จำนวนมากรองรับขนาดหน้า 16 KB โดยเฉพาะหากคุณสร้าง SDK เองหรือใช้ SDK ที่สร้างไว้ล่วงหน้าเวอร์ชันล่าสุด อย่างไรก็ตาม เนื่องจาก SDK บางเวอร์ชันหรือ SDK ที่สร้างไว้ล่วงหน้าบางรายการไม่รองรับ 16 KB คุณจึงควรตรวจสอบเว็บไซต์ของผู้ให้บริการ SDK แต่ละรายเพื่อดูว่าควรใช้ SDK เวอร์ชันใดกับ 16 KB
ทดสอบแอปในสภาพแวดล้อมแบบ 16 KB
หลังจากสร้างแอปที่รองรับอุปกรณ์แบบ 16 KB แล้ว คุณจะต้อง ทดสอบแอปในสภาพแวดล้อมแบบ 16 KB เพื่อดูว่าแอปของคุณมี การถดถอยหรือไม่ โดยทำตามขั้นตอนต่อไปนี้
ตั้งค่า Android 15 SDK ขึ้นไป
ตั้งค่าสภาพแวดล้อมการทดสอบอย่างใดอย่างหนึ่งต่อไปนี้
เปิดอุปกรณ์ทดสอบ จากนั้นเรียกใช้คำสั่งต่อไปนี้เพื่อยืนยันว่า อุปกรณ์ใช้สภาพแวดล้อมแบบ 16 KB
adb shell getconf PAGE_SIZEคำสั่งควรแสดงค่า
16384เรียกใช้คำสั่ง
zipalignต่อไปนี้เพื่อยืนยันว่าแอปของคุณ สอดคล้องกับ 16 KB โดยที่ APK_NAME คือชื่อของ ไฟล์ APK ของแอปzipalign -c -P 16 -v 4 APK_NAME.apkทดสอบแอปอย่างละเอียด โดยมุ่งเน้นที่ส่วนต่างๆ ที่อาจได้รับผลกระทบจาก การเปลี่ยนอินสแตนซ์ของโค้ดที่อ้างอิงขนาดหน้าเว็บที่เฉพาะเจาะจง
ตั้งค่าโปรแกรมจำลองของ Android ด้วยอิมเมจระบบแบบ 16 KB
หากต้องการตั้งค่าสภาพแวดล้อมแบบ 16 KB โดยใช้โปรแกรมจำลองของ Android ให้ทำตามขั้นตอนต่อไปนี้
- ใน Android Studio ให้คลิกเครื่องมือ > เครื่องมือจัดการ SDK
ในแท็บแพลตฟอร์ม SDK ให้เลือกแสดงรายละเอียดแพ็กเกจ จากนั้นขยาย ส่วน Android VanillaIceCream ขึ้นไป แล้วเลือกอิมเมจระบบของโปรแกรมจำลองต่อไปนี้อย่างใดอย่างหนึ่งหรือทั้ง 2 รายการ ขึ้นอยู่กับอุปกรณ์เสมือนที่คุณต้องการสร้าง
- อิมเมจระบบ ARM 64 v8a ขนาดหน้าหน่วยความจำ 16 KB ของ Google APIs Experimental
- Google APIs Experimental 16 KB Page Size Intel x86_64 Atom System รูปภาพ
คลิกใช้ > ตกลงเพื่อดาวน์โหลดอิมเมจระบบที่คุณเลือก
ทำตามขั้นตอนเพื่อตั้งค่าอุปกรณ์เสมือนจริงสำหรับ Android 15 และเมื่อระบบแจ้งให้เลือกอิมเมจระบบ ให้เลือกอิมเมจระบบขนาด 16 KB ที่คุณดาวน์โหลด หากระบบไม่แนะนำโดยอัตโนมัติ คุณจะดูอิมเมจระบบขนาด 16 KB ได้ในแท็บอิมเมจอื่นๆ
เปิดโปรแกรมจำลอง
หลังจากตั้งค่า Android Emulator และอุปกรณ์เสมือนเสร็จแล้ว ให้เปิด โปรแกรมจำลองจากเมนูอุปกรณ์เป้าหมาย หรือจากบรรทัดคำสั่ง
เปิดใช้โหมด 16 KB ในอุปกรณ์โดยใช้ตัวเลือกสำหรับนักพัฒนาแอป
สลับตัวเลือกสำหรับนักพัฒนาแอปบูตโดยใช้หน้าหน่วยความจำขนาด 16 KB เพื่อบูตอุปกรณ์ในโหมด 16 KB
ใน Android 15 เวอร์ชัน QPR คุณสามารถใช้ตัวเลือกสำหรับนักพัฒนาแอปที่มีในอุปกรณ์บางรุ่นเพื่อบูตอุปกรณ์ในโหมด 16 KB และทำการทดสอบในอุปกรณ์ได้ ก่อนใช้ตัวเลือกสำหรับนักพัฒนาซอฟต์แวร์ ให้ไปที่การตั้งค่า > ระบบ > การอัปเดตซอฟต์แวร์ แล้วใช้การอัปเดตที่มี
ตัวเลือกสำหรับนักพัฒนาแอปนี้พร้อมใช้งานในอุปกรณ์ต่อไปนี้
Pixel 8 และ 8 Pro (ที่ใช้ Android 15 QPR1 ขึ้นไป)
Pixel 8a (ใช้ Android 15 QPR1 ขึ้นไป)
Pixel 9, 9 Pro และ 9 Pro XL (ใช้ Android 15 QPR2 ขึ้นไป)
Pixel 9a (ใช้ Android 16 ขึ้นไป)
โหมด 16 KB สำหรับความเข้ากันได้แบบย้อนหลัง
คำเตือนในโหมดความเข้ากันได้กับขนาดหน้า
ตัวเลือกความเข้ากันได้แบบย้อนหลัง 16 KB จะพร้อมใช้งานเมื่ออุปกรณ์ใช้ เคอร์เนลขนาด 16 KB Package Manager จะเรียกใช้แอปในโหมดความเข้ากันได้แบบย้อนหลังขนาด 16 KB เมื่อตรงตามเงื่อนไขต่อไปนี้
- หากแอปมีไฟล์ ELF (นามสกุล
.so) ที่มีการจัดแนวส่วน LOAD เป็น 4 KB - หาก APK ที่ซิปมีไฟล์ ELF ที่ไม่ได้บีบอัดซึ่งมีขนาด 4 KB และจัดเรียง ZIP
หากเครื่องมือจัดการแพ็กเกจเปิดใช้โหมดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับแอป แอปจะแสดงประกาศเตือนเมื่อเปิดใช้ครั้งแรกว่าแอปทำงานในโหมดความเข้ากันได้แบบย้อนหลัง 16 KB
โหมดความเข้ากันได้แบบย้อนหลัง 16 KB ช่วยให้แอปบางแอปทำงานได้ แต่เพื่อให้มีความน่าเชื่อถือและความเสถียรสูงสุด แอปควรยังคงจัดแนว 16 KB
ในหน้าข้อมูลแอป ให้สลับการตั้งค่าเรียกใช้แอปด้วย โหมดเข้ากันได้กับขนาดหน้าในส่วนขั้นสูงเพื่อเปิดหรือปิดใช้โหมดความเข้ากันได้แบบย้อนหลัง 16 KB สำหรับแอปที่เฉพาะเจาะจง การตั้งค่านี้จะปรากฏขึ้นเมื่ออุปกรณ์ทำงานด้วย ขนาดหน้า 16 KB เท่านั้น
การตั้งค่าโหมดเข้ากันได้กับขนาดหน้า
หากต้องการบังคับให้ใช้การรองรับการทำงานแบบย้อนกลับขนาด 16 KB สำหรับทุกแอปในอุปกรณ์ ให้ทำดังนี้
adb shell setprop bionic.linker.16kb.app_compat.enabled true
adb shell setprop pm.16kb.app_compat.disabled false
วิธีปิดการรองรับการทำงานแบบย้อนกลับขนาด 16 KB สำหรับทุกแอปในอุปกรณ์
adb shell setprop bionic.linker.16kb.app_compat.enabled false
adb shell setprop pm.16kb.app_compat.disabled true
ใน Android 17 คุณยังบังคับให้ปิดการรองรับแบบย้อนกลับ 16 KB สำหรับทุกแอปและ ทำให้ไบนารีที่ไม่เข้ากันหยุดทำงานทันทีได้ด้วย
adb shell setprop bionic.linker.16kb.app_compat.enabled fatal
adb shell setprop pm.16kb.app_compat.disabled true
ตั้งค่าพร็อพเพอร์ตี้ android:pageSizeCompat เป็นเปิดใช้หรือปิดใช้เพื่อเปิดหรือปิดโหมดความเข้ากันได้แบบย้อนหลังสำหรับแอปที่เฉพาะเจาะจงใน AndroidManifest.xml เมื่อตั้งค่าพร็อพเพอร์ตี้นี้ แอปจะไม่แสดงคำเตือนโหมด Backcompat เมื่อเปิดตัว