บันทึกฮีปดัมป์เพื่อดูว่าออบเจ็กต์ใดในแอปใช้หน่วยความจำอยู่ ณ เวลาที่บันทึก และระบุหน่วยความจำรั่วไหลหรือลักษณะการจัดสรรหน่วยความจำที่ทำให้เกิดการกระตุก ค้าง และแม้กระทั่งแอปขัดข้อง การดัมพ์ฮีปจะมีประโยชน์อย่างยิ่งหลังจากเซสชันของผู้ใช้ที่ขยายเวลาออกไป ซึ่งอาจแสดงออบเจ็กต์ที่ยังคงอยู่ในหน่วยความจำซึ่งไม่ควรอยู่ที่นั่นอีกต่อไป
หน้านี้อธิบายเครื่องมือที่ Android Studio มีให้เพื่อรวบรวมและวิเคราะห์ฮีปดัมป์ หรือจะตรวจสอบหน่วยความจำของแอปจากบรรทัดคำสั่งด้วย dumpsys และดูเหตุการณ์การเก็บขยะ (GC) ใน Logcat ก็ได้
เหตุใดคุณจึงควรทำโปรไฟล์หน่วยความจำของแอป
Android มีสภาพแวดล้อมหน่วยความจำที่มีการจัดการ เมื่อ Android พิจารณาว่าแอปของคุณไม่ได้ใช้ออบเจ็กต์บางอย่างอีกต่อไป ตัวรวบรวมขยะจะปล่อยหน่วยความจำที่ไม่ได้ใช้กลับไปยังฮีป วิธีที่ Android ค้นหาหน่วยความจำที่ไม่ได้ใช้ได้รับการปรับปรุงอย่างต่อเนื่อง แต่ในบางจุดของ Android ทุกเวอร์ชัน ระบบต้องหยุดโค้ดของคุณชั่วคราวเป็นเวลาสั้นๆ โดยส่วนใหญ่แล้ว การหยุดชั่วคราวจะสังเกตเห็นได้ยาก อย่างไรก็ตาม หากแอปของคุณจัดสรรหน่วยความจำเร็วกว่าที่ระบบจะรวบรวมได้ แอปอาจล่าช้าในขณะที่ตัวรวบรวมเพิ่มหน่วยความจำให้เพียงพอต่อการจัดสรรของคุณ ความล่าช้าอาจทำให้แอปข้ามเฟรมและทำให้เกิดความล่าช้าที่สังเกตเห็นได้
แม้ว่าแอปจะไม่ได้ทำงานช้า แต่หากมีหน่วยความจำรั่วไหล แอปจะยังคงเก็บหน่วยความจำนั้นไว้แม้ว่าจะทำงานอยู่เบื้องหลังก็ตาม ลักษณะการทำงานนี้อาจทำให้ประสิทธิภาพหน่วยความจำของระบบที่เหลือช้าลงโดยการบังคับให้เกิดเหตุการณ์การเก็บขยะที่ไม่จำเป็น ในที่สุด ระบบจะถูกบังคับให้หยุดกระบวนการของแอปเพื่อเรียกคืนหน่วยความจำ จากนั้นเมื่อผู้ใช้กลับมาที่แอปของคุณ กระบวนการของแอปจะต้องรีสตาร์ทใหม่ทั้งหมด
ดูข้อมูลเกี่ยวกับแนวทางปฏิบัติในการเขียนโปรแกรมที่ช่วยลดการใช้หน่วยความจำของแอปได้ที่หัวข้อจัดการหน่วยความจำของแอป
ภาพรวมของฮีปดัมป์
หากต้องการบันทึกฮีพดัมพ์ ให้เลือกงานวิเคราะห์การใช้งานหน่วยความจำ (ฮีพดัมพ์) (ใช้ Profiler: เรียกใช้ "แอป" เป็นแบบแก้ไขข้อบกพร่องได้ (ข้อมูลที่สมบูรณ์)) เพื่อบันทึกฮีพดัมพ์ ขณะดัมพ์ฮีป ปริมาณหน่วยความจำ Java อาจเพิ่มขึ้นชั่วคราว ซึ่งเป็นเรื่องปกติเนื่องจากฮีปดัมป์เกิดขึ้นในกระบวนการเดียวกับแอปของคุณและต้องใช้หน่วยความจำบางส่วนเพื่อรวบรวมข้อมูล หลังจากบันทึกฮีปดัมป์แล้ว คุณจะเห็นข้อมูลต่อไปนี้
รายการชั้นเรียนจะแสดงข้อมูลต่อไปนี้
- การจัดสรร: จำนวนการจัดสรรในฮีป
ขนาดเนทีฟ: จำนวนหน่วยความจำเนทีฟทั้งหมดที่ออบเจ็กต์ประเภทนี้ใช้ (เป็นไบต์) คุณจะเห็นหน่วยความจำที่นี่สำหรับออบเจ็กต์บางรายการที่จัดสรรใน Java เนื่องจาก Android ใช้หน่วยความจำแบบเนทีฟสำหรับคลาสเฟรมเวิร์กบางคลาส เช่น
Bitmapขนาดระดับออบเจ็กต์: จำนวนหน่วยความจำ Java ทั้งหมดที่ออบเจ็กต์ประเภทนี้ใช้ (เป็นไบต์)
ขนาดที่คงไว้: ขนาดหน่วยความจำทั้งหมดที่คงไว้เนื่องจากอินสแตนซ์ทั้งหมดของคลาสนี้ (หน่วยเป็นไบต์)
ใช้เมนูฮีปเพื่อกรองฮีปที่ต้องการ ดังนี้
- ฮีปของแอป (ค่าเริ่มต้น): ฮีปหลักที่แอปจัดสรรหน่วยความจำ
- ฮีปรูปภาพ: อิมเมจบูตของระบบ ซึ่งมีคลาสที่โหลดไว้ล่วงหน้าระหว่างการเปิดเครื่อง การจัดสรรที่นี่จะไม่ย้ายหรือหายไป
- Zygote heap: ฮีปแบบคัดลอกเมื่อเขียนซึ่งเป็นที่มาของกระบวนการแอปในระบบ Android
ใช้เมนูแบบเลื่อนลงของการจัดเรียงเพื่อเลือกวิธีจัดเรียงการจัดสรร ดังนี้
- จัดเรียงตามชั้นเรียน (ค่าเริ่มต้น): จัดกลุ่มการจัดสรรทั้งหมดตามชื่อชั้นเรียน
- จัดเรียงตามแพ็กเกจ: จัดกลุ่มการจัดสรรทั้งหมดตามชื่อแพ็กเกจ
ใช้เมนูแบบเลื่อนลงของชั้นเรียนเพื่อกรองกลุ่มชั้นเรียน ดังนี้
- คลาสทั้งหมด (ค่าเริ่มต้น): แสดงคลาสทั้งหมด รวมถึงคลาสจากไลบรารีและการขึ้นต่อกัน
- แสดงกิจกรรม/การรั่วไหลของ Fragment: แสดงคลาสที่ทำให้หน่วยความจำรั่วไหล
- แสดงคลาสของโปรเจ็กต์: แสดงเฉพาะคลาสที่โปรเจ็กต์กำหนดไว้
คลิกชื่อคลาสเพื่อเปิดแผงอินสแตนซ์ แต่ละอินสแตนซ์ที่แสดงจะมีข้อมูลต่อไปนี้
- ความลึก: จำนวนฮอปที่สั้นที่สุดจากรูท GC ไปยังอินสแตนซ์ที่เลือก
- ขนาดเนทีฟ: ขนาดของอินสแตนซ์นี้ในหน่วยความจำเนทีฟ คอลัมน์นี้จะแสดงใน Android 7.0 ขึ้นไปเท่านั้น
- ขนาดระดับออบเจ็กต์: ขนาดของอินสแตนซ์นี้ในหน่วยความจำ Java
- ขนาดที่คงไว้: ขนาดของหน่วยความจำที่อินสแตนซ์นี้ครอบครอง (ตามแผนผัง Dominator)
คลิกอินสแตนซ์เพื่อแสดงรายละเอียดอินสแตนซ์ รวมถึงช่องและการอ้างอิง ประเภทช่องและประเภทการอ้างอิงที่พบบ่อยคือประเภทที่มีโครงสร้าง
,
อาร์เรย์
,
และประเภทข้อมูลพื้นฐาน
ใน Java คลิกขวาที่ช่องหรือข้อมูลอ้างอิงเพื่อไปยังอินสแตนซ์หรือบรรทัดที่เกี่ยวข้องในซอร์สโค้ด
- ฟิลด์: แสดงฟิลด์ทั้งหมดในอินสแตนซ์นี้
- การอ้างอิง: แสดงการอ้างอิงทั้งหมดไปยังออบเจ็กต์ที่ไฮไลต์ในแท็บอินสแตนซ์
ตรวจหาบิตแมปที่ซ้ำกัน
นอกจากนี้ คุณยังตรวจหาบิตแมปที่ซ้ำซ้อนในมุมมองฮีปดัมป์ได้ตั้งแต่ Android Studio Narwhal 4 เป็นต้นไป
วิธีค้นหาอีเมลมีดังนี้
- เปิดแท็บ Profiler ใน Android Studio
- คลิก ฮีปดัมป์ (หรือวิเคราะห์การใช้งานหน่วยความจำ) แล้วคลิกบันทึกเพื่อจับภาพสแนปชอตของสถานะหน่วยความจำปัจจุบันของแอป
- สแกนผลการวิเคราะห์เพื่อหาสามเหลี่ยมคำเตือนสีเหลือง ⚠️ ซึ่ง Android Studio ใช้เพื่อแจ้งว่ามีการจัดเก็บบิตแมปที่ซ้ำกันหลายครั้ง
- หรือไปที่ส่วนหัวของเครื่องมือวิเคราะห์ เลือกกรองตาม: แล้วเลือกการตั้งค่าบิตแมปที่ซ้ำกัน
- คลิกรายการที่ถูกแจ้งว่าไม่เหมาะสมเพื่อเปิดแผงแสดงตัวอย่างบิตแมป ซึ่งจะช่วยให้คุณเห็นได้อย่างชัดเจนว่ารูปภาพใดเป็นรูปภาพที่ละเมิดซ้ำ
- ใช้การยืนยันด้วยภาพนั้นเพื่อติดตามตรรกะการโหลดที่ซ้ำซ้อนในโค้ดและใช้กลยุทธ์การแคชที่ดีขึ้น
ค้นหาหน่วยความจำรั่วไหล
หากต้องการกรองคลาสที่อาจเชื่อมโยงกับหน่วยความจำรั่วไหลอย่างรวดเร็ว ให้เปิดเมนูแบบเลื่อนลงของคลาส แล้วเลือกแสดงการรั่วไหลของกิจกรรม/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