บันทึกฮีพดัมพ์

บันทึกฮีปดัมป์เพื่อดูว่าออบเจ็กต์ใดในแอปใช้หน่วยความจำมากที่สุด ณ เวลาที่บันทึก และระบุ หน่วยความจำรั่วไหล หรือลักษณะการทำงานของการจัดสรรหน่วยความจำที่ทำให้เกิดการกระตุก ค้าง และแม้แต่แอปขัดข้อง การบันทึกฮีปดัมป์หลังจากเซสชันของผู้ใช้ที่ยาวนานจะเป็นประโยชน์อย่างยิ่ง เนื่องจากอาจแสดงออบเจ็กต์ที่ยังอยู่ในหน่วยความจำซึ่งไม่ควรอยู่แล้ว

หน้านี้อธิบายเครื่องมือที่ Android Studio มีไว้เพื่อรวบรวมและวิเคราะห์ฮีปดัมป์ หรือคุณจะตรวจสอบหน่วยความจำของแอปจาก บรรทัดคำสั่งด้วย dumpsys และยัง ดูเหตุการณ์ระบบจัดการหน่วยความจำที่ไม่ใช้แล้ว (GC) ใน Logcat ได้อีกด้วย

เหตุผลที่ควรสร้างโปรไฟล์หน่วยความจำของแอป

Android มีสภาพแวดล้อมหน่วยความจำที่มีการจัดการเมื่อ Android กำหนดว่า แอปของคุณไม่ได้ใช้ออบเจ็กต์บางรายการอีกต่อไป ตัวเก็บขยะจะปล่อย หน่วยความจำที่ไม่ได้ใช้กลับไปยังฮีป Android ปรับปรุงวิธีค้นหาหน่วยความจำที่ไม่ได้ใช้อยู่เสมอ แต่ในบางจุดของ Android ทุกเวอร์ชัน ระบบจะต้องหยุดโค้ดของคุณชั่วคราว โดยส่วนใหญ่แล้วการหยุดชั่วคราวจะสังเกตเห็นได้ยาก อย่างไรก็ตาม หากแอปจัดสรรหน่วยความจำเร็วกว่าที่ระบบจะรวบรวมได้ แอปของคุณอาจล่าช้าในขณะที่ตัวเก็บขยะปล่อยหน่วยความจำให้เพียงพอต่อการจัดสรร ความล่าช้าอาจทำให้แอปข้ามเฟรมและทำให้เกิดความช้าที่มองเห็นได้

แม้ว่าแอปของคุณจะไม่ได้แสดงอาการช้า แต่หากหน่วยความจำรั่วไหล แอปก็อาจเก็บหน่วยความจำนั้นไว้แม้ว่าจะอยู่ในเบื้องหลังก็ตาม ลักษณะการทำงานนี้อาจทำให้ประสิทธิภาพหน่วยความจำของระบบส่วนอื่นๆ ช้าลงโดยบังคับให้เกิดเหตุการณ์ระบบจัดการหน่วยความจำที่ไม่ใช้แล้วที่ไม่จำเป็น ในที่สุด ระบบจะบังคับให้หยุดกระบวนการของแอปเพื่อเรียกคืนหน่วยความจำ จากนั้นเมื่อผู้ใช้กลับมาที่แอป กระบวนการของแอปจะต้องรีสตาร์ททั้งหมด

ดูข้อมูลเกี่ยวกับแนวทางปฏิบัติในการเขียนโปรแกรมที่ช่วยลดการใช้หน่วยความจำของแอปได้ที่ อ่าน [จัดการหน่วยความจำของแอป]memory

ภาพรวมของฮีปดัมป์

หากต้องการบันทึกฮีปดัมป์ ให้เลือกงาน วิเคราะห์การใช้หน่วยความจำ (ฮีปดัมป์) (ใช้ Profiler: run 'app' as debuggable (complete data)) เพื่อบันทึกฮีป ดัมป์ ขณะที่กำลังดัมป์ฮีป ปริมาณหน่วยความจำ Java อาจเพิ่มขึ้นชั่วคราว ซึ่งเป็นเรื่องปกติเนื่องจากฮีปดัมป์เกิดขึ้นในกระบวนการเดียวกับแอปและต้องใช้หน่วยความจำบางส่วนเพื่อรวบรวมข้อมูล หลังจากบันทึกฮีปดัมป์แล้ว คุณจะเห็นข้อมูลต่อไปนี้

มุมมองฮีปดัมป์ใน Android Studio Profiler

รายการคลาสจะแสดงข้อมูลต่อไปนี้

  • การจัดสรร: จำนวนการจัดสรรในฮีป
  • ขนาดเนทีฟ: ปริมาณหน่วยความจำเนทีฟทั้งหมดที่ประเภทออบเจ็กต์นี้ใช้ (หน่วยเป็น ไบต์) คุณจะเห็นหน่วยความจำที่นี่สำหรับออบเจ็กต์บางรายการที่จัดสรรใน Java เนื่องจาก Android ใช้หน่วยความจำเนทีฟสำหรับคลาสเฟรมเวิร์กบางรายการ เช่น Bitmap

  • ขนาดตื้น: ปริมาณหน่วยความจำ Java ทั้งหมดที่ประเภทออบเจ็กต์นี้ใช้ (หน่วยเป็น ไบต์)

  • ขนาดที่เก็บไว้: ขนาดหน่วยความจำทั้งหมดที่เก็บไว้เนื่องจากอินสแตนซ์ทั้งหมดของ คลาสนี้ (หน่วยเป็นไบต์)

ใช้เมนูฮีปเพื่อกรองฮีปบางรายการ

  • ฮีปของแอป (ค่าเริ่มต้น): ฮีปหลักที่แอปจัดสรรหน่วยความจำ
  • ฮีปรูปภาพ: อิมเมจบูตของระบบ ซึ่งมีคลาสที่โหลดไว้ล่วงหน้าในระหว่างเวลาบูต การจัดสรรที่นี่จะไม่ย้ายหรือหายไป
  • ฮีป Zygote: ฮีปคัดลอกเมื่อเขียนที่กระบวนการของแอปแยกออกมาใน ระบบ Android

ใช้เมนูแบบเลื่อนลงการจัดเรียงเพื่อเลือกวิธีจัดเรียงการจัดสรร

  • จัดเรียงตามคลาส (ค่าเริ่มต้น): จัดกลุ่มการจัดสรรทั้งหมดตามชื่อคลาส
  • จัดเรียงตามแพ็กเกจ: จัดกลุ่มการจัดสรรทั้งหมดตามชื่อแพ็กเกจ

ใช้เมนูแบบเลื่อนลงคลาสเพื่อกรองกลุ่มคลาส

  • คลาสทั้งหมด (ค่าเริ่มต้น): แสดงคลาสทั้งหมด รวมถึงคลาสจากไลบรารี และการขึ้นต่อกัน
  • แสดงหน่วยความจำรั่วไหลของกิจกรรม/Fragment: แสดงคลาสที่ทำให้เกิดหน่วยความจำรั่วไหล
  • แสดงคลาสของโปรเจ็กต์: แสดงเฉพาะคลาสที่กำหนดโดยโปรเจ็กต์

คลิกชื่อคลาสเพื่อเปิดบานหน้าต่างอินสแตนซ์ อินสแตนซ์แต่ละรายการที่แสดงจะมีข้อมูลต่อไปนี้

  • ความลึก: จำนวนการข้ามที่สั้นที่สุดจากราก GC ไปยังอินสแตนซ์ที่เลือก
  • ขนาดเนทีฟ: ขนาดของอินสแตนซ์นี้ในหน่วยความจำเนทีฟ คอลัมน์นี้จะแสดงเฉพาะใน Android 7.0 ขึ้นไป
  • ขนาดตื้น: ขนาดของอินสแตนซ์นี้ในหน่วยความจำ Java
  • ขนาดที่เก็บไว้: ขนาดหน่วยความจำที่อินสแตนซ์นี้ครอบครอง (ตาม แผนผังผู้ครอบครอง)

คลิกอินสแตนซ์เพื่อแสดงรายละเอียดอินสแตนซ์ ซึ่งรวมถึงฟิลด์ และการอ้างอิง ประเภทฟิลด์และการอ้างอิงทั่วไปคือประเภทที่มีโครงสร้าง , อาร์เรย์ , และประเภทข้อมูลดั้งเดิม ใน Java คลิกขวาที่ฟิลด์หรือการอ้างอิงเพื่อไปยังอินสแตนซ์หรือบรรทัดที่เกี่ยวข้องในซอร์สโค้ด

  • ฟิลด์: แสดงฟิลด์ทั้งหมดในอินสแตนซ์นี้
  • การอ้างอิง: แสดงการอ้างอิงทั้งหมดไปยังออบเจ็กต์ที่ไฮไลต์ในแท็บ อินสแตนซ์
มุมมองอินสแตนซ์ ฟิลด์ และการอ้างอิง ในหน้าต่างเครื่องมือฮีปดัมป์

ตรวจหาบิตแมปที่ซ้ำกัน

นอกจากนี้ คุณยังตรวจหาบิตแมปที่ซ้ำซ้อนได้ในมุมมองฮีปดัมป์ตั้งแต่ Android Studio Narwhal 4 เป็นต้นไป

วิธีตรวจหาบิตแมปที่ซ้ำกันมีดังนี้

  1. เปิดแท็บ Profiler ใน Android Studio
  2. คลิกฮีปดัมป์ (หรือวิเคราะห์การใช้หน่วยความจำ) แล้วคลิกบันทึกเพื่อถ่ายภาพสถานะหน่วยความจำปัจจุบันของแอป
  3. สแกนผลการวิเคราะห์เพื่อหาเครื่องหมายสามเหลี่ยมคำเตือนสีเหลือง ⚠️ ซึ่ง Android Studio ใช้เพื่อแจ้งบิตแมปที่ซ้ำกันซึ่งจัดเก็บไว้หลายครั้ง
    • หรือไปที่ส่วนหัวของ Profiler เลือกกรองตาม: แล้วเลือกการตั้งค่าบิตแมปที่ซ้ำกัน
  4. คลิกรายการที่แจ้งเพื่อเปิดบานหน้าต่างการแสดงตัวอย่างบิตแมป ซึ่งจะช่วยให้คุณเห็นได้อย่างชัดเจนว่ารูปภาพใดที่ซ้ำกัน
  5. ใช้การยืนยันด้วยภาพเพื่อติดตามตรรกะการโหลดที่ซ้ำซ้อนในโค้ดและใช้กลยุทธ์การแคชที่ดีขึ้น
มองหาบิตแมปที่ซ้ำกันโดยใช้เครื่องหมายสามเหลี่ยมคำเตือนสีเหลือง ⚠️

ค้นหาหน่วยความจำรั่วไหล

หากต้องการกรองคลาสที่อาจเกี่ยวข้องกับหน่วยความจำรั่วไหลอย่างรวดเร็ว ให้เปิดเมนูแบบเลื่อนลงคลาสแล้วเลือกแสดงหน่วยความจำรั่วไหลของกิจกรรม/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

แหล่งข้อมูลเพิ่มเติม