บันทึกฮีปดัมป์เพื่อดูว่าออบเจ็กต์ใดในแอปใช้หน่วยความจำมากที่สุด ณ เวลาที่บันทึก และระบุ หน่วยความจำรั่วไหล หรือลักษณะการทำงานของการจัดสรรหน่วยความจำที่ทำให้เกิดการกระตุก ค้าง และแม้แต่แอปขัดข้อง การบันทึกฮีปดัมป์หลังจากเซสชันของผู้ใช้ที่ยาวนานจะเป็นประโยชน์อย่างยิ่ง เนื่องจากอาจแสดงออบเจ็กต์ที่ยังอยู่ในหน่วยความจำซึ่งไม่ควรอยู่แล้ว
หน้านี้อธิบายเครื่องมือที่ Android Studio มีไว้เพื่อรวบรวมและวิเคราะห์ฮีปดัมป์ หรือคุณจะตรวจสอบหน่วยความจำของแอปจาก
บรรทัดคำสั่งด้วย dumpsys และยัง
ดูเหตุการณ์ระบบจัดการหน่วยความจำที่ไม่ใช้แล้ว (GC) ใน Logcat ได้อีกด้วย
เหตุผลที่ควรสร้างโปรไฟล์หน่วยความจำของแอป
Android มีสภาพแวดล้อมหน่วยความจำที่มีการจัดการ เมื่อ Android พบว่า แอปของคุณไม่ได้ใช้ออบเจ็กต์บางรายการอีกต่อไป ตัวเก็บขยะจะปล่อย หน่วยความจำที่ไม่ได้ใช้กลับไปยังฮีป Android ปรับปรุงวิธีค้นหาหน่วยความจำที่ไม่ได้ใช้อยู่เสมอ แต่ในบางจุดของ Android ทุกเวอร์ชัน ระบบจะต้องหยุดโค้ดของคุณชั่วคราว โดยส่วนใหญ่แล้วการหยุดชั่วคราวจะสังเกตเห็นได้ยาก อย่างไรก็ตาม หากแอปจัดสรรหน่วยความจำเร็วกว่าที่ระบบจะรวบรวมได้ แอปของคุณอาจล่าช้าในขณะที่ตัวเก็บขยะปล่อยหน่วยความจำให้เพียงพอต่อการจัดสรรของคุณ ความล่าช้าอาจทำให้แอปข้ามเฟรมและทำให้เกิดความช้าที่มองเห็นได้
แม้ว่าแอปของคุณจะไม่ได้แสดงอาการช้า แต่หากหน่วยความจำรั่วไหล แอปก็อาจเก็บหน่วยความจำนั้นไว้แม้ว่าจะอยู่ในเบื้องหลังก็ตาม ลักษณะการทำงานนี้อาจทำให้ประสิทธิภาพหน่วยความจำของระบบส่วนอื่นๆ ช้าลงโดยบังคับให้เกิดเหตุการณ์ระบบจัดการหน่วยความจำที่ไม่ใช้แล้วที่ไม่จำเป็น ในที่สุด ระบบจะบังคับให้หยุดกระบวนการของแอปเพื่อเรียกคืนหน่วยความจำ จากนั้นเมื่อผู้ใช้กลับมาที่แอป กระบวนการของแอปจะต้องรีสตาร์ทโดยสมบูรณ์
ดูข้อมูลเกี่ยวกับแนวทางปฏิบัติในการเขียนโปรแกรมที่ช่วยลดการใช้หน่วยความจำของแอปได้ที่ อ่านจัดการหน่วยความจำของแอป
ภาพรวมฮีปดัมป์
หากต้องการบันทึกฮีปดัมป์ ให้เลือกงาน วิเคราะห์การใช้หน่วยความจำ (ฮีปดัมป์) (ใช้ Profiler: run 'app' as debuggable (complete data)) เพื่อบันทึกฮีป ดัมป์ ขณะที่บันทึกฮีปดัมป์ ปริมาณหน่วยความจำ Java อาจเพิ่มขึ้นชั่วคราว ซึ่งเป็นเรื่องปกติเนื่องจากฮีปดัมป์เกิดขึ้นในกระบวนการเดียวกับแอปและต้องใช้หน่วยความจำบางส่วนเพื่อรวบรวมข้อมูล หลังจากบันทึกฮีปดัมป์แล้ว คุณจะเห็นข้อมูลต่อไปนี้
รายการคลาสจะแสดงข้อมูลต่อไปนี้
- การจัดสรร: จำนวนการจัดสรรในฮีป
ขนาดเนทีฟ: ปริมาณหน่วยความจำเนทีฟทั้งหมดที่ใช้โดยออบเจ็กต์ประเภทนี้ (หน่วยเป็น ไบต์) คุณจะเห็นหน่วยความจำที่นี่สำหรับออบเจ็กต์บางรายการที่จัดสรรใน Java เนื่องจาก Android ใช้หน่วยความจำเนทีฟสำหรับคลาสเฟรมเวิร์กบางรายการ เช่น
Bitmapขนาดตื้น: ปริมาณหน่วยความจำ Java ทั้งหมดที่ใช้โดยออบเจ็กต์ประเภทนี้ (หน่วยเป็น ไบต์)
ขนาดที่เก็บไว้: ขนาดหน่วยความจำทั้งหมดที่เก็บไว้เนื่องจากอินสแตนซ์ทั้งหมดของ คลาสนี้ (หน่วยเป็นไบต์)
ใช้เมนูฮีปเพื่อกรองไปยังฮีปบางรายการ
- ฮีปของแอป (ค่าเริ่มต้น): ฮีปหลักที่แอปจัดสรรหน่วยความจำ
- ฮีปรูปภาพ: อิมเมจบูตของระบบ ซึ่งมีคลาสที่โหลดไว้ล่วงหน้า ระหว่างเวลาบูต การจัดสรรที่นี่จะไม่ย้ายหรือหายไป
- ฮีป Zygote: ฮีปคัดลอกเมื่อเขียนที่กระบวนการของแอปแยกออกมาใน ระบบ Android
ใช้เมนูแบบเลื่อนลงการจัดเรียงเพื่อเลือกวิธีจัดเรียงการจัดสรร
- จัดเรียงตามคลาส (ค่าเริ่มต้น): จัดกลุ่มการจัดสรรทั้งหมดตามชื่อคลาส
- จัดเรียงตามแพ็กเกจ: จัดกลุ่มการจัดสรรทั้งหมดตามชื่อแพ็กเกจ
ใช้เมนูแบบเลื่อนลงคลาสเพื่อกรองไปยังกลุ่มคลาส
- คลาสทั้งหมด (ค่าเริ่มต้น): แสดงคลาสทั้งหมด รวมถึงคลาสจากไลบรารี และการขึ้นต่อกัน
- แสดงหน่วยความจำรั่วไหลของกิจกรรม/Fragment: แสดงคลาสที่ทำให้เกิดหน่วยความจำรั่วไหล
- แสดงคลาสโปรเจ็กต์: แสดงเฉพาะคลาสที่กำหนดโดยโปรเจ็กต์
คลิกชื่อคลาสเพื่อเปิดบานหน้าต่างอินสแตนซ์ อินสแตนซ์แต่ละรายการที่แสดงจะมีข้อมูลต่อไปนี้
- ความลึก: จำนวนการข้ามที่สั้นที่สุดจากราก GC ไปยังอินสแตนซ์ที่เลือก
- ขนาดเนทีฟ: ขนาดของอินสแตนซ์นี้ในหน่วยความจำเนทีฟ คอลัมน์นี้จะแสดงเฉพาะใน Android 7.0 ขึ้นไป
- ขนาดตื้น: ขนาดของอินสแตนซ์นี้ในหน่วยความจำ Java
- ขนาดที่เก็บไว้: ขนาดหน่วยความจำที่อินสแตนซ์นี้ครอบครอง (ตาม แผนผังผู้ครอบครอง))
คลิกอินสแตนซ์เพื่อแสดงรายละเอียดอินสแตนซ์ ซึ่งรวมถึงฟิลด์
และการอ้างอิง ประเภทฟิลด์และการอ้างอิงทั่วไปคือประเภทที่มีโครงสร้าง
,
อาร์เรย์
,
และประเภทข้อมูลดั้งเดิม
ใน Java คลิกขวาที่ฟิลด์หรือการอ้างอิงเพื่อไปยังอินสแตนซ์หรือบรรทัดที่เกี่ยวข้องในโค้ดที่มา
- ฟิลด์: แสดงฟิลด์ทั้งหมดในอินสแตนซ์นี้
- การอ้างอิง: แสดงการอ้างอิงทั้งหมดไปยังออบเจ็กต์ที่ไฮไลต์ในแท็บ อินสแตนซ์
ตรวจหาบิตแมปที่ซ้ำกัน
นอกจากนี้ คุณยังตรวจหาบิตแมปที่ซ้ำซ้อนได้ในมุมมองฮีปดัมป์ตั้งแต่ Android Studio Narwhal 4 เป็นต้นไป
วิธีตรวจหาบิตแมปที่ซ้ำกันมีดังนี้
- เปิดแท็บ Profiler ใน Android Studio
- คลิกฮีปดัมป์ (หรือวิเคราะห์การใช้หน่วยความจำ) แล้วคลิกบันทึกเพื่อบันทึกสถานะหน่วยความจำปัจจุบันของแอป
- สแกนผลการวิเคราะห์เพื่อหาเครื่องหมายสามเหลี่ยมคำเตือนสีเหลือง ⚠️ ซึ่ง Android Studio ใช้เพื่อแจ้งบิตแมปที่ซ้ำกันซึ่งจัดเก็บไว้หลายครั้ง
- หรือไปที่ส่วนหัวของ Profiler เลือกกรองตาม: แล้วเลือกการตั้งค่าบิตแมปที่ซ้ำกัน
- คลิกรายการที่แจ้งเพื่อเปิดบานหน้าต่างการแสดงตัวอย่างบิตแมป ซึ่งจะช่วยให้คุณเห็นได้อย่างชัดเจนว่ารูปภาพใดที่ซ้ำกัน
- ใช้การยืนยันด้วยภาพเพื่อติดตามตรรกะการโหลดที่ซ้ำซ้อนในโค้ดและใช้กลยุทธ์การแคชที่ดีขึ้น
ค้นหาหน่วยความจำรั่วไหล
หากต้องการกรองไปยังคลาสที่อาจเกี่ยวข้องกับหน่วยความจำรั่วไหลอย่างรวดเร็ว ให้เปิดเมนูแบบเลื่อนลงคลาสแล้วเลือกแสดงหน่วยความจำรั่วไหลของกิจกรรม/Fragment Android Studio
จะแสดงคลาสที่ระบบคิดว่าบ่งบอกถึงหน่วยความจำรั่วไหลสำหรับ
Activity และ
Fragment อินสแตนซ์ในแอป
หากต้องการค้นหาหน่วยความจำรั่วไหลด้วยตนเองมากขึ้น ให้เรียกดูรายการคลาสและอินสแตนซ์เพื่อค้นหาออบเจ็กต์ที่มีขนาดที่เก็บไว้ ใหญ่ มองหาหน่วยความจำรั่วไหลที่เกิดจากสาเหตุใดสาเหตุหนึ่งต่อไปนี้
- การอ้างอิง
ActivityหรือContextที่มีอายุการใช้งานยาวนานซึ่งอาจทำให้กราฟองค์ประกอบ Compose ที่โฮสต์รั่วไหล (เช่นComposeViewและองค์ประกอบย่อยที่ใช้ร่วมกัน) - ออบเจ็กต์สถานะ Jetpack Compose (
MutableState) ตัวยึดสถานะ หรือแลมบ์ดาที่เก็บContextรั่วไหล - ลืมล้างข้อมูล Listener หรือ Observer ในบล็อก
onDisposeของDisposableEffect - คลาสภายในที่ไม่ใช่แบบคงที่ เช่น
Runnableซึ่งสามารถเก็บอินสแตนซ์Activityได้ - แคชที่เก็บออบเจ็กต์ไว้นานกว่าที่จำเป็น
เมื่อพบหน่วยความจำรั่วไหลที่อาจเกิดขึ้น ให้ใช้แท็บฟิลด์ และการอ้างอิง ในรายละเอียดอินสแตนซ์ เพื่อข้ามไปยังอินสแตนซ์หรือบรรทัดโค้ดที่มาที่ต้องการ
กระตุ้นให้เกิดหน่วยความจำรั่วไหลเพื่อทำการทดสอบ
หากต้องการวิเคราะห์การใช้งานหน่วยความจำ คุณควรทดสอบโค้ดของแอปและพยายามบังคับให้เกิดหน่วยความจำรั่วไหล วิธีหนึ่งในการกระตุ้นให้เกิดหน่วยความจำรั่วไหลในแอปคือการปล่อยให้แอปทำงานสักพักก่อนที่จะตรวจสอบฮีป หน่วยความจำรั่วไหลอาจค่อยๆ เพิ่มขึ้นไปจนถึงด้านบนของการจัดสรรในฮีป อย่างไรก็ตาม ยิ่งหน่วยความจำรั่วไหลมีขนาดเล็ก คุณก็ยิ่งต้องเรียกใช้แอปนานขึ้นเพื่อดูหน่วยความจำรั่วไหล
นอกจากนี้ คุณยังกระตุ้นให้เกิดหน่วยความจำรั่วไหลได้ด้วยวิธีใดวิธีหนึ่งต่อไปนี้
- หมุนอุปกรณ์จากแนวตั้งเป็นแนวนอนและกลับไปกลับมาหลายครั้งขณะอยู่ในสถานะกิจกรรมต่างๆ การหมุนอุปกรณ์มักทำให้แอป
เกิดหน่วยความจำรั่วไหลของ
Activity(และด้วยเหตุนี้จึงทำให้แผนผัง UI ของ Compose ที่โฮสต์และ แผนผังสถานะที่เกี่ยวข้องรั่วไหล) หากแอปมีการอ้างอิงActivityหรือContextภายในตัวยึดสถานะหรือการดำเนินการแบบอะซิงโครนัส - สลับไปมาระหว่างแอปของคุณกับแอปอื่นขณะอยู่ในสถานะกิจกรรมต่างๆ เช่น ไปที่หน้าจอหลัก แล้วกลับมาที่แอป
ส่งออกและนำเข้าการบันทึกฮีปดัมป์
คุณสามารถ
ส่งออกและนำเข้าไฟล์ฮีปดัมป์
จากแท็บการบันทึกที่ผ่านมาใน Profiler Android Studio จะบันทึกการบันทึกเป็นไฟล์ .hprof
หรือหากต้องการใช้เครื่องมือวิเคราะห์ไฟล์ .hprof อื่น เช่น
jhat,
คุณต้องแปลงไฟล์ .hprof จากรูปแบบ Android เป็นรูปแบบไฟล์ .hprof ของ Java SE หากต้องการแปลงรูปแบบไฟล์ ให้ใช้เครื่องมือ hprof-conv ที่มีให้ในไดเรกทอรี {android_sdk}/platform-tools/ เรียกใช้คำสั่ง hprof-conv พร้อมอาร์กิวเมนต์ 2 รายการ ได้แก่ ชื่อไฟล์ .hprof เดิมและตำแหน่งที่จะเขียนไฟล์ .hprof ที่แปลงแล้ว ซึ่งรวมถึงชื่อไฟล์ .hprof ใหม่ ตัวอย่าง
hprof-conv heap-original.hprof heap-converted.hprof