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

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

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

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

ถ่ายสแนปชอต

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

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

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

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

ขนาดรวมของออบเจ็กต์ที่เข้าถึงได้

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

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

ล้างสแนปชอต

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

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

ดูสแนปชอต

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

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

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

มุมมองสรุป

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

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

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

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

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

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

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

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

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

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

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

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

  • ฟังก์ชันในตัว เช่น Array หรือ Object
  • องค์ประกอบ HTML ที่จัดกลุ่มตามแท็ก เช่น <div>, <a>, <img> และอื่นๆ
  • ฟังก์ชันที่คุณกำหนดในโค้ด
  • หมวดหมู่พิเศษที่ไม่ได้อิงจากเครื่องมือสร้าง

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

(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. เปิดแผงหน่วยความจำ เลือก สแนปชอตฮีป แล้วเปิด แสดงภายใน (รวมถึงรายละเอียดเฉพาะการใช้งานเพิ่มเติม)
  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. ถ่ายภาพสแนปชอตกองขยะภาพที่สองและเปลี่ยนมุมมองเป็นการเปรียบเทียบ โดยเปรียบเทียบกับภาพสแนปชอต 1

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

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

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

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

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

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

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

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

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

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

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

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

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

ปุ่ม &quot;ละเว้นเครื่องมือเก็บนี้&quot; ในเมนูแบบเลื่อนลง

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

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

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

ตั้งชื่อฟังก์ชันเพื่อแยกความแตกต่างของ Closure

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

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

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