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

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

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

เหตุใดคุณจึงควรทำโปรไฟล์หน่วยความจำของแอป

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

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

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

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

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

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

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

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

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

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

ใช้เมนูฮีปเพื่อกรองฮีปที่ต้องการ ดังนี้

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

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

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

ใช้เมนูแบบเลื่อนลงของชั้นเรียนเพื่อกรองกลุ่มชั้นเรียน ดังนี้

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

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

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

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

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

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

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

วิธีค้นหาอีเมลมีดังนี้

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

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

หากต้องการกรองคลาสที่อาจเชื่อมโยงกับหน่วยความจำรั่วไหลอย่างรวดเร็ว ให้เปิดเมนูแบบเลื่อนลงของคลาส แล้วเลือกแสดงการรั่วไหลของกิจกรรม/Fragment Android Studio จะแสดงคลาสที่คิดว่าบ่งชี้ถึงหน่วยความจำรั่วไหลสำหรับอินสแตนซ์ Activity และ Fragment ในแอป

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

  • การอ้างอิงที่มีอายุการใช้งานยาวนานไปยัง Activity หรือ Context ที่อาจทำให้กราฟ Composition ของ Compose ที่โฮสต์รั่วไหล (เช่น ComposeView และ Composable ย่อย)
  • ออบเจ็กต์ State ของ Jetpack Compose (MutableState), ตัวเก็บสถานะ หรือ Lambda ที่บันทึก Context รั่วไหล
  • การลืมล้าง Listener หรือ Observer ในบล็อก onDispose ของ DisposableEffect
  • คลาสภายในที่ไม่ใช่แบบคงที่ เช่น Runnable ซึ่งสามารถเก็บอินสแตนซ์ Activity ไว้ได้
  • แคชที่เก็บออบเจ็กต์ไว้นานเกินความจำเป็น

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

ทริกเกอร์หน่วยความจำรั่วไหลเพื่อการทดสอบ

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

นอกจากนี้ คุณยังทริกเกอร์หน่วยความจำรั่วไหลได้ด้วยวิธีใดวิธีหนึ่งต่อไปนี้

  • หมุนอุปกรณ์จากแนวตั้งเป็นแนวนอนและหมุนกลับอีกครั้งหลายๆ ครั้งขณะอยู่ในสถานะกิจกรรมต่างๆ การหมุนอุปกรณ์มักทำให้แอปเกิดการรั่วไหลของ Activity (และส่งผลให้เกิดการรั่วไหลของโครงสร้าง UI ของ Compose ที่โฮสต์และโครงสร้างสถานะที่เกี่ยวข้อง) หากแอปเก็บการอ้างอิงไปยัง Activity หรือ Context ไว้ภายในการดำเนินการแบบอะซิงโครนัสหรือตัวเก็บสถานะ
  • สลับไปมาระหว่างแอปของคุณกับแอปอื่นขณะอยู่ในสถานะกิจกรรมที่แตกต่างกัน เช่น ไปที่หน้าจอหลัก แล้วกลับไปที่แอป

ส่งออกและนำเข้าการบันทึกฮีปดัมป์

คุณสามารถส่งออกและนำเข้าไฟล์ฮีปดัมป์จากแท็บการบันทึกที่ผ่านมาในเครื่องมือวิเคราะห์ประสิทธิภาพได้ 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

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