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

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

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

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

ถ่ายสแนปชอต

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

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

ประเภทการโปรไฟล์ที่เลือกและอินสแตนซ์ 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;
}

ฟังก์ชันที่มีชื่อใน Closure

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

เครื่องมือวิเคราะห์ฮีปสามารถแสดงการพึ่งพาแบบ 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 มีค่าเป็น 0 เท่านั้นที่ต้นไม้ทั้งหมดที่อยู่ภายใต้ #tree จะเป็นผู้สมัครสําหรับ GC

ต้นไม้ย่อย DOM

ได้ที่นี่