ในแพลตฟอร์ม Android ระบบจะพยายามใช้หน่วยความจำของระบบ (RAM) ให้มากที่สุดเท่าที่จะเป็นไปได้ และทำการเพิ่มประสิทธิภาพหน่วยความจำต่างๆ เพื่อเพิ่มพื้นที่ว่างเมื่อจำเป็น การเพิ่มประสิทธิภาพเหล่านี้อาจส่งผลเสียต่อเกม ไม่ว่าจะทำให้เกมช้าลงหรือหยุดทำงานไปเลย ดูข้อมูลเพิ่มเติมเกี่ยวกับการเพิ่มประสิทธิภาพเหล่านี้ได้ ในหัวข้อ การจัดสรรหน่วยความจำระหว่างกระบวนการ
เพื่อให้อุปกรณ์มีความเสถียร ตั้งแต่ Android 17 (ระดับ API 37) เป็นต้นไป ระบบจะเริ่มบังคับใช้ขีดจำกัดหน่วยความจำของแอปตาม RAM ทั้งหมดของอุปกรณ์ หาก แอปเกินขีดจำกัดเหล่านั้น Android จะหยุดกระบวนการโดยไม่มี สแต็กเทรซที่เกี่ยวข้อง
หน้านี้จะอธิบายขั้นตอนที่คุณสามารถทำเพื่อหลีกเลี่ยงสภาวะหน่วยความจำเหลือน้อย ที่ส่งผลต่อเกม
ตอบสนองต่อ onTrimMemory()
ระบบใช้
onTrimMemory()
เพื่อแจ้งเตือนแอปของคุณเกี่ยวกับเหตุการณ์ในวงจรของแอป ซึ่งเป็นโอกาสที่ดีสำหรับแอปของคุณ
ในการลดการใช้งานหน่วยความจำโดยสมัครใจและหลีกเลี่ยงการถูกLow-Memory Killer (LMK)
หยุดทำงานเพื่อปล่อยหน่วยความจำให้แอปอื่นๆ ใช้
หากระบบปิดแอปของคุณในเบื้องหลัง ครั้งถัดไปที่ผู้ใช้เปิดแอป ผู้ใช้จะพบกับCold Start ที่ช้า แอปที่ลดการใช้งานหน่วยความจำเมื่อเข้าสู่เบื้องหลังมีโอกาสน้อยที่จะถูกปิดในเบื้องหลัง
เมื่อตอบสนองต่อเหตุการณ์การตัดแต่ง สิ่งที่ดีที่สุดคือการปล่อยการจัดสรรหน่วยความจำขนาดใหญ่
ที่ไม่จำเป็นในทันทีและสามารถสร้างใหม่ได้ตามต้องการ ตัวอย่างเช่น
หากแอปมีแคชของบิตแมปที่ถอดรหัสจากรูปภาพที่บีบอัดซึ่งจัดเก็บไว้ในเครื่อง
การตัดแต่งหรือล้างแคชนี้เพื่อตอบสนองต่อ
TRIM_MEMORY_UI_HIDDEN มักจะเป็นความคิดที่ดี
Kotlin
class MainActivity : AppCompatActivity(), ComponentCallbacks2 { override fun onTrimMemory(level: Int) { if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } }
Java
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 { public void onTrimMemory(int level) { switch (level) { if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } } }
ใช้หน่วยความจำอย่างประหยัด
จัดสรรหน่วยความจำอย่างรอบคอบเพื่อหลีกเลี่ยงไม่ให้หน่วยความจำหมด สิ่งที่ควรพิจารณา ได้แก่
- ขนาดของ RAM จริง: เกมมักจะใช้ RAM จริงในอุปกรณ์ประมาณ ¼ ถึง ½
- ขนาด zRAM สูงสุด: zRAM ที่มากขึ้นหมายความว่าเกมอาจมีหน่วยความจำมากขึ้น
เพื่อจัดสรร จำนวนนี้อาจแตกต่างกันไปตามอุปกรณ์ ให้มองหา
SwapTotalใน/proc/meminfoเพื่อดูค่านี้ - การใช้งานหน่วยความจำของระบบปฏิบัติการ: อุปกรณ์ที่กำหนด RAM ให้กับกระบวนการของระบบมากกว่าจะเหลือหน่วยความจำสำหรับเกมของคุณน้อยลง ระบบจะปิดกระบวนการของเกม ก่อนที่จะปิดกระบวนการของระบบ
- การใช้งานหน่วยความจำของแอปที่ติดตั้ง: ทดสอบเกมในอุปกรณ์ที่มีแอปจำนวนมากติดตั้งไว้ แอปโซเชียลมีเดียและแอปแชทต้องทำงานอย่างต่อเนื่องและส่งผลต่อปริมาณหน่วยความจำที่ว่าง
หากไม่สามารถใช้งบประมาณหน่วยความจำแบบอนุรักษ์นิยม ให้ใช้แนวทางที่ยืดหยุ่นกว่า
หากระบบพบปัญหาหน่วยความจำเหลือน้อย ให้ลดปริมาณหน่วยความจำ
ที่เกมใช้ เช่น จัดสรรพื้นผิวที่มีความละเอียดต่ำกว่าหรือจัดเก็บ
Shader น้อยลงเพื่อตอบสนองต่อ onTrimMemory() แนวทางการจัดสรรหน่วยความจำแบบไดนามิกนี้ต้องใช้ความพยายามจากนักพัฒนาแอปมากขึ้น โดยเฉพาะอย่างยิ่งในระยะการออกแบบเกม
หลีกเลี่ยงการ Thrash
การ Thrashจะเกิดขึ้นเมื่อหน่วยความจำว่างเหลือน้อย แต่ไม่น้อยพอที่จะปิดเกม
ในกรณีนี้ kswapd ได้เรียกคืนหน้าเว็บที่เกมยังคงต้องการ ดังนั้นจึงพยายามโหลดหน้าเว็บจากหน่วยความจำอีกครั้ง มีพื้นที่ไม่เพียงพอ ระบบจึงสลับหน้า
ออกไปเรื่อยๆ (การสลับอย่างต่อเนื่อง)
การติดตามระบบจะรายงานสถานการณ์นี้เป็นเธรด
ที่ kswapd ทำงานอย่างต่อเนื่อง
อาการอย่างหนึ่งของการเกิด Thrashing คือเวลาเฟรมที่นาน ซึ่งอาจนานถึง 1 วินาทีหรือมากกว่า โปรดลดปริมาณหน่วยความจำที่ใช้ของเกมเพื่อแก้ไขปัญหานี้
ใช้เครื่องมือที่มี
Android มีชุดเครื่องมือที่จะช่วยให้เข้าใจวิธีที่ระบบ จัดการหน่วยความจำ
Meminfo
เครื่องมือนี้จะรวบรวมสถิติหน่วยความจำเพื่อแสดงปริมาณ หน่วยความจำ PSS ที่จัดสรรและหมวดหมู่ที่ใช้
พิมพ์สถิติ meminfo โดยใช้วิธีใดวิธีหนึ่งต่อไปนี้
- ใช้คำสั่ง
adb shell dumpsys meminfo package-name - ใช้การเรียก
MemoryInfoจาก Android Debug API
สถิติ PrivateDirty แสดง
ปริมาณ RAM ภายในกระบวนการที่เพจไปยังดิสก์ไม่ได้และไม่ได้แชร์
กับกระบวนการอื่นๆ ระบบจะใช้จำนวนเงินส่วนใหญ่ได้เมื่อปิดกระบวนการดังกล่าว
จุดติดตามหน่วยความจำ
Tracepoint ของหน่วยความจำจะติดตามปริมาณหน่วยความจำ RSS ที่เกมของคุณใช้ การคำนวณการใช้งานหน่วยความจำ RSS เร็วกว่าการคำนวณการใช้งาน PSS มาก เนื่องจากคำนวณได้เร็วกว่า RSS จึงแสดงรายละเอียดที่ละเอียดยิ่งขึ้นเกี่ยวกับการเปลี่ยนแปลงขนาดหน่วยความจำเพื่อให้วัดการใช้งานหน่วยความจำสูงสุดได้แม่นยำยิ่งขึ้น ดังนั้น คุณจึงสังเกตเห็นจุดสูงสุดที่อาจทำให้เกมใช้หน่วยความจำจนหมดได้ง่ายขึ้น
Perfetto และการติดตามแบบยาว
Perfetto เป็นชุดเครื่องมือสำหรับรวบรวม ข้อมูลประสิทธิภาพและหน่วยความจำในอุปกรณ์และแสดงใน UI บนเว็บ ซึ่งรองรับการติดตามที่ยาวนานเท่าใดก็ได้เพื่อให้คุณดูการเปลี่ยนแปลง RSS เมื่อเวลาผ่านไปได้ นอกจากนี้ คุณยังออกคําค้นหา SQL ในข้อมูลที่สร้างขึ้นเพื่อการประมวลผลแบบออฟไลน์ได้ด้วย เปิดใช้การติดตามระยะยาวจากแอปการติดตามระบบ ตรวจสอบว่าได้เปิดใช้หมวดหมู่memory:Memory สำหรับการติดตามแล้ว สำหรับการตรวจสอบหน่วยความจำที่กำหนดเองในการพัฒนาและการทดสอบ คุณยังใช้ (เบต้า) heapprofd API ได้ด้วย
heapprofd
heapprofd เป็นเครื่องมือติดตามหน่วยความจำ
ซึ่งเป็นส่วนหนึ่งของ Perfetto เครื่องมือนี้ช่วยคุณค้นหาหน่วยความจำรั่วได้โดยแสดงตำแหน่งที่จัดสรรหน่วยความจำโดยใช้ malloc heapprofd สามารถเริ่มต้นได้โดยใช้สคริปต์ Python และเนื่องจากเครื่องมือนี้มีค่าใช้จ่ายต่ำ จึงไม่ส่งผลต่อ
ประสิทธิภาพเหมือนเครื่องมืออื่นๆ เช่น Malloc Debug
รายงานข้อบกพร่อง
bugreport เป็นเครื่องมือบันทึกเพื่อดูว่าเกมขัดข้องหรือไม่
เนื่องจากหน่วยความจำไม่เพียงพอ เอาต์พุตของเครื่องมือนี้มีรายละเอียดมากกว่าการใช้
logcat มาก ซึ่งมีประโยชน์สำหรับการแก้ไขข้อบกพร่องของหน่วยความจำเนื่องจากจะแสดงว่าเกมขัดข้อง
เนื่องจากหน่วยความจำไม่เพียงพอหรือ LMK เป็นตัวหยุดการทำงาน
ดูข้อมูลเพิ่มเติมได้ที่บันทึกและอ่านรายงานข้อบกพร่อง