จัดการความจำอย่างมีประสิทธิภาพในเกม

ในแพลตฟอร์ม 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 เป็นตัวหยุดการทำงาน

ดูข้อมูลเพิ่มเติมได้ที่บันทึกและอ่านรายงานข้อบกพร่อง