บันทึกฮีพสแนปชอต

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

ดูวิธีบันทึกฮีปสแนปชอตด้วยหน่วยความจำ > โปรไฟล์ > ฮีพสแนปชอต และค้นหาการรั่วไหลของหน่วยความจำ

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

ถ่ายสแนปชอต

วิธีถ่ายฮีพสแนปชอต

  1. ในหน้าที่ต้องการสร้างโปรไฟล์ ให้เปิดเครื่องมือสำหรับนักพัฒนาเว็บ แล้วไปที่แผงหน่วยความจำ
  2. เลือกประเภทการทำโปรไฟล์ Heap Snapshot ของ radio_button_checked จากนั้นเลือกอินสแตนซ์ VM ของ JavaScript แล้วคลิกTake Snapshot

ประเภทการสร้างโปรไฟล์และอินสแตนซ์ VM ของ JavaScript ที่เลือก

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

ขนาดรวมของวัตถุที่เข้าถึงได้

สแนปชอตจะแสดงเฉพาะวัตถุจากกราฟหน่วยความจำที่เข้าถึงได้จากวัตถุส่วนกลาง การบันทึกสแนปชอตจะเริ่มต้นด้วยการเก็บข้อมูลขยะ

ฮีพสแนปชอตของออบเจ็กต์รายการที่กระจัดกระจาย

ล้างสแนปชอต

หากต้องการนำสแนปชอตทั้งหมดออก ให้คลิกบล็อก ล้างโปรไฟล์ทั้งหมด โดยทำดังนี้

ล้างโปรไฟล์ทั้งหมด

ดูสแนปชอต

หากต้องการตรวจสอบสแนปชอตจากมุมมองที่ต่างกันเพื่อวัตถุประสงค์ที่ต่างกัน ให้เลือกมุมมองใดมุมมองหนึ่งจากเมนูแบบเลื่อนลงที่ด้านบน

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

มุมมองสรุปที่เลือกไว้จากเมนูแบบเลื่อนลงที่ด้านบน

มุมมองสรุป

ในขั้นต้น ฮีพสแนปชอตจะเปิดขึ้นในมุมมองสรุปที่แสดงรายการเครื่องมือสร้างในคอลัมน์ คุณสามารถขยายตัวสร้างเพื่อดูวัตถุที่มีการสร้างขึ้น

มุมมองสรุปที่มีเครื่องมือสร้างแบบขยาย

หากต้องการกรองเครื่องมือสร้างที่ไม่เกี่ยวข้องออก ให้พิมพ์ชื่อที่คุณต้องการตรวจสอบในตัวกรองชั้นเรียนที่ด้านบนของมุมมองสรุป

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

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

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

ตัวกรองเครื่องมือสร้าง

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

หากต้องการใช้ตัวกรองเหล่านี้ ให้เลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้จากเมนูแบบเลื่อนลงทางด้านขวาสุดในแถบการทำงาน

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

รายการพิเศษในหน้าสรุป

นอกเหนือจากการจัดกลุ่มตามตัวสร้างแล้ว มุมมองสรุปยังจัดกลุ่มออบเจ็กต์ตามสิ่งต่อไปนี้

  • ฟังก์ชันในตัว เช่น Array หรือ Object
  • ฟังก์ชันที่คุณกำหนดในโค้ด
  • หมวดหมู่พิเศษที่ไม่ได้อิงจากเครื่องมือสร้าง

รายการเครื่องมือสร้าง

(array)

หมวดหมู่นี้จะมีออบเจ็กต์ที่มีลักษณะคล้ายอาร์เรย์ภายในหลายรายการ ซึ่งไม่สอดคล้องกับออบเจ็กต์ที่แสดงใน JavaScript โดยตรง

เช่น เนื้อหาของออบเจ็กต์ JavaScript Array จะจัดเก็บอยู่ในออบเจ็กต์ภายในรองชื่อ (object elements)[] เพื่อให้ปรับขนาดได้ง่ายขึ้น ในทำนองเดียวกัน พร็อพเพอร์ตี้ที่มีชื่อในออบเจ็กต์ JavaScript มักจะจัดเก็บอยู่ในออบเจ็กต์ภายในรองที่ชื่อ (object properties)[] ซึ่งแสดงอยู่ในหมวดหมู่ (array) ด้วย

(compiled code)

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

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

(concatenated string)

เมื่อ V8 เชื่อม 2 สตริงเข้าด้วยกัน เช่น ด้วยโอเปอเรเตอร์ JavaScript + ระบบอาจเลือกแสดงผลลัพธ์ภายในเป็น "สตริงที่เชื่อมต่อ" หรือที่เรียกว่าโครงสร้างข้อมูล Rope

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

InternalNode

หมวดหมู่นี้แสดงออบเจ็กต์ที่จัดสรรนอก V8 เช่น ออบเจ็กต์ C++ ที่ Blink กำหนด

หากต้องการดูชื่อคลาส C++ ให้ใช้ Chrome สำหรับการทดสอบ แล้วทำตามขั้นตอนต่อไปนี้

  1. เปิดเครื่องมือสำหรับนักพัฒนาเว็บและเปิดการตั้งค่า การตั้งค่า > การทดสอบ > ช่องทำเครื่องหมาย แสดงตัวเลือกเพื่อแสดงตัวเลือกภายในในฮีปสแนปชอต
  2. เปิดแผงหน่วยความจำ เลือก radio_button_checked สแนปชอตฮีป แล้วเปิดradio_button_checked แสดงภายใน (รวมถึงรายละเอียดเฉพาะการใช้งานเพิ่มเติม)
  3. จำลองปัญหาที่ทำให้ InternalNode คงความทรงจำไว้จำนวนมาก
  4. ถ่ายฮีพสแนปชอต ในสแนปชอตนี้ วัตถุมีชื่อคลาส C++ แทนที่จะเป็น InternalNode
(object shape)

ตามที่อธิบายไว้ในส่วนคุณสมบัติที่รวดเร็วใน V8 V8 จะติดตามคลาสที่ซ่อนอยู่ (หรือรูปร่าง) เพื่อให้วัตถุหลายรายการที่มีคุณสมบัติเดียวกันในลำดับเดียวกันแสดงได้อย่างมีประสิทธิภาพ หมวดหมู่นี้มีคลาสที่ซ่อนอยู่ที่เรียกว่า system / Map (ไม่เกี่ยวข้องกับ JavaScript Map) และข้อมูลที่เกี่ยวข้อง

(sliced string)

เมื่อ V8 ต้องใช้สตริงย่อย เช่น เมื่อเรียกโค้ด JavaScript String.prototype.substring() ระบบ V8 อาจเลือกจัดสรรออบเจ็กต์สตริงที่แบ่งส่วนแทนการคัดลอกอักขระที่เกี่ยวข้องทั้งหมดจากสตริงต้นฉบับ ออบเจ็กต์ใหม่นี้มีตัวชี้ไปยังสตริงต้นฉบับและอธิบายช่วงของอักขระจากสตริงต้นฉบับที่จะใช้

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

system / Context

ออบเจ็กต์ภายในประเภท system / Context มีตัวแปรภายในจาก closure ซึ่งเป็นขอบเขต JavaScript ที่ฟังก์ชันที่ซ้อนกันเข้าถึงได้

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

(system)

หมวดหมู่นี้มีออบเจ็กต์ภายในหลายรายการที่ (ยัง) ไม่ได้จัดหมวดหมู่ให้มีความหมายมากขึ้น

มุมมองการเปรียบเทียบ

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

วิธีตรวจสอบว่าการดำเนินการบางอย่างไม่ทำให้เกิดการรั่วไหล

  1. สร้างฮีพสแนปชอตก่อนดำเนินการ
  2. ดำเนินการ กล่าวคือ โต้ตอบกับหน้าเว็บในลักษณะที่คุณคิดว่าอาจเป็นสาเหตุของการรั่วไหล
  3. ดำเนินการย้อนกลับ กล่าวคือ ให้โต้ตอบตรงกันข้ามและทำซ้ำอีก 2-3 ครั้ง
  4. ถ่ายฮีพสแนปชอตที่ 2 แล้วเปลี่ยนมุมมองเป็นการเปรียบเทียบ เพื่อเปรียบเทียบกับสแนปชอต 1

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

เปรียบเทียบกับสแนปชอต 1

มุมมองที่เก็บ

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

มุมมองนี้มีจุดเข้าหลายจุดดังนี้

  • ออบเจ็กต์ DOMWindow ออบเจ็กต์ส่วนกลางสำหรับโค้ด JavaScript
  • รูทของ GC รูท GC ที่ใช้โดยเครื่องมือรวบรวมขยะของ VM รูท GC อาจประกอบด้วยแผนที่ออบเจ็กต์ในตัว, ตารางสัญลักษณ์, สแต็กเทรด VM, แคชการคอมไพล์, ขอบเขตแฮนเดิล และแฮนเดิลส่วนกลาง
  • ออบเจ็กต์ดั้งเดิม มีการ "พุช" ออบเจ็กต์เบราว์เซอร์ภายในเครื่องเสมือน JavaScript เพื่ออนุญาตให้ทำงานอัตโนมัติ เช่น โหนด DOM และกฎ CSS

มุมมองที่เก็บ

ส่วนเครื่องมือเก็บ

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

ส่วนเครื่องมือเก็บ

ในตัวอย่างนี้ ระบบจะเก็บรักษาสตริงที่เลือกตามพร็อพเพอร์ตี้ x ของอินสแตนซ์ Item

ละเว้นเครื่องมือเก็บ

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

ตัวเลือก "ละเว้นเครื่องมือเก็บนี้" ในเมนูแบบเลื่อนลง

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

ค้นหาวัตถุที่เฉพาะเจาะจง

หากต้องการค้นหาออบเจ็กต์ในฮีปที่รวบรวม คุณจะค้นหาได้โดยใช้ Ctrl + F แล้วป้อนรหัสออบเจ็กต์

ตั้งชื่อฟังก์ชันเพื่อแยกความแตกต่างระหว่างการปิด

การตั้งชื่อฟังก์ชันจะช่วยให้แยกความแตกต่างระหว่างการปิดในสแนปชอตได้

ตัวอย่างเช่น โค้ดต่อไปนี้ไม่ใช้ฟังก์ชันที่มีชื่อ

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function() { // this is NOT a named function
    return largeStr;
  };

  return lC;
}

ขณะที่ตัวอย่างนี้:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

ฟังก์ชันที่มีชื่ออยู่ในการปิด

ค้นหาการรั่วไหลของ DOM

เครื่องมือสร้างโปรไฟล์ฮีปมีความสามารถในการแสดงทรัพยากร Dependency แบบ 2 ทิศทางระหว่างออบเจ็กต์เนทีฟของเบราว์เซอร์ (โหนด DOM และกฎ CSS) และออบเจ็กต์ JavaScript วิธีนี้ช่วยให้ค้นพบการรั่วไหลที่มองไม่เห็นซึ่งเกิดจากการที่ต้นไม้ย่อย DOM ถูกแยกออกโดยลืมลอยอยู่

การรั่วไหลของ DOM อาจยิ่งใหญ่กว่าที่คุณคิด ลองดูตัวอย่างต่อไปนี้ ระบบเก็บรวบรวมขยะของ #tree เมื่อใด

  var select = document.querySelector;
  var treeRef = select("#tree");
  var leafRef = select("#leaf");
  var body = select("body");

  body.removeChild(treeRef);

  //#tree can't be GC yet due to treeRef
  treeRef = null;

  //#tree can't be GC yet due to indirect
  //reference from leafRef

  leafRef = null;
  //#NOW #tree can be garbage collected

#leaf จะรักษาการอ้างอิงไปยังระดับบนสุด (parentNode) และซ้ำซ้อนไปจนถึง #tree ดังนั้นเฉพาะเมื่อ leafRef มีค่าเป็นโมฆะ คือต้นไม้ทั้งใน #tree ที่ผู้สมัครรับเลือกตั้งเป็น GC

แผนผังย่อย DOM