ดูวิธีบันทึกสแนปชอตฮีปด้วยหน่วยความจํา > โปรไฟล์ > สแนปชอตฮีป และค้นหาการรั่วไหลของหน่วยความจํา
เครื่องมือสร้างโปรไฟล์ฮีปจะแสดงการกระจายหน่วยความจำโดยออบเจ็กต์ JavaScript และโหนด DOM ที่เกี่ยวข้องของหน้าเว็บ ใช้ข้อมูลนี้เพื่อสร้างฮีพสแนปชอต JS วิเคราะห์กราฟหน่วยความจำ เปรียบเทียบสแนปชอต และค้นหาการรั่วไหลของหน่วยความจำ ดูข้อมูลเพิ่มเติมได้ที่โครงสร้างการเก็บรักษาออบเจ็กต์
ถ่ายสแนปชอต
วิธีถ่ายฮีพสแนปชอต
- ในหน้าที่ต้องการสร้างโปรไฟล์ ให้เปิดเครื่องมือสำหรับนักพัฒนาเว็บและไปที่แผงหน่วยความจำ
- เลือกประเภทการทำโปรไฟล์ Heap Snapshot ของ จากนั้นเลือกอินสแตนซ์ VM ของ JavaScript แล้วคลิกTake Snapshot
เมื่อแผงหน่วยความจำโหลดและแยกวิเคราะห์สแนปชอต ขนาดรวมของออบเจ็กต์ 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 สำหรับการทดสอบ แล้วทำตามขั้นตอนต่อไปนี้
- เปิดเครื่องมือสำหรับนักพัฒนาเว็บและเปิด การตั้งค่า > การทดสอบ > แสดงตัวเลือกในการเปิดเผยภายในในฮีพสแนปชอต
- เปิดแผงหน่วยความจำ เลือก สแนปชอตฮีป แล้วเปิด แสดงภายใน (รวมถึงรายละเอียดเฉพาะการใช้งานเพิ่มเติม)
- จำลองปัญหาที่ทำให้
InternalNode
คงความทรงจำไว้จำนวนมาก - ถ่ายฮีพสแนปชอต ในภาพหน้าจอนี้ ออบเจ็กต์จะมีชื่อคลาส 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)
หมวดหมู่นี้มีออบเจ็กต์ภายในหลายรายการที่ (ยัง) ไม่ได้จัดหมวดหมู่ให้มีความหมายมากขึ้น
มุมมองการเปรียบเทียบ
มุมมองการเปรียบเทียบช่วยให้คุณค้นหาวัตถุที่รั่วไหลได้โดยเปรียบเทียบภาพนิ่งหลายภาพ เช่น การดำเนินการและการดำเนินการย้อนกลับ เช่น การเปิดและปิดเอกสาร ไม่ควรทิ้งออบเจ็กต์ไว้
วิธีตรวจสอบว่าการดำเนินการบางอย่างไม่ทำให้เกิดการรั่วไหล
- สร้างฮีพสแนปชอตก่อนดำเนินการ
- ดำเนินการ กล่าวคือ โต้ตอบกับหน้าเว็บในลักษณะที่คุณคิดว่าอาจเป็นสาเหตุของการรั่วไหล
- ดำเนินการย้อนกลับ กล่าวคือ ให้โต้ตอบกลับกันและทำซ้ำ 2-3 ครั้ง
- ถ่ายภาพสแนปชอตกองขยะภาพที่สองและเปลี่ยนมุมมองเป็นการเปรียบเทียบ โดยเปรียบเทียบกับภาพสแนปชอต 1
มุมมองการเปรียบเทียบจะแสดงความแตกต่างระหว่างสแนปชอต 2 รายการ เมื่อขยายยอดรวม แสดงอินสแตนซ์ของออบเจ็กต์ที่เพิ่ม และถูกลบ
มุมมองที่เก็บ
มุมมองคอนเทนเนอร์คือ "มุมมองจากมุมสูง" ของโครงสร้างออบเจ็กต์ของแอปพลิเคชัน ซึ่งช่วยให้คุณดูการปิดฟังก์ชัน สังเกตออบเจ็กต์ภายใน VM ที่รวมกันเป็นออบเจ็กต์ JavaScript และทำความเข้าใจปริมาณหน่วยความจำที่แอปพลิเคชันใช้ในระดับที่ต่ำมาก
มุมมองนี้มีจุดเข้าหลายจุดดังนี้
- ออบเจ็กต์ DOMWindow ออบเจ็กต์ส่วนกลางสำหรับโค้ด JavaScript
- รูท GC รูท GC ที่ใช้โดยเครื่องมือรวบรวมขยะของ VM รูท GC อาจประกอบด้วยแผนที่ออบเจ็กต์ในตัว, ตารางสัญลักษณ์, สแต็กเทรด VM, แคชการคอมไพล์, ขอบเขตแฮนเดิล และแฮนเดิลส่วนกลาง
- ออบเจ็กต์ดั้งเดิม ออบเจ็กต์ "พุช" ของเบราว์เซอร์ ภายในเครื่องเสมือน JavaScript เพื่ออนุญาตการทำงานอัตโนมัติ เช่น โหนด DOM และกฎ CSS
ส่วนเครื่องมือเก็บ
ส่วนเครื่องมือเก็บที่ด้านล่างของแผงหน่วยความจำจะแสดงออบเจ็กต์ที่ชี้ไปยังออบเจ็กต์ที่เลือกในมุมมอง แผงหน่วยความจำจะอัปเดตส่วนเครื่องมือเก็บเมื่อคุณเลือกออบเจ็กต์อื่นในข้อมูลพร็อพเพอร์ตี้ใดๆ ยกเว้นสถิติ
ในตัวอย่างนี้ ระบบจะเก็บรักษาสตริงที่เลือกตามพร็อพเพอร์ตี้ x
ของอินสแตนซ์ Item
ละเว้นเครื่องมือเก็บ
คุณสามารถซ่อนเครื่องมือเก็บเพื่อดูออบเจ็กต์อื่นๆ ที่เก็บรายการที่เลือกไว้ได้ เมื่อใช้ตัวเลือกนี้ คุณจะไม่ต้องนำเครื่องมือเก็บนี้ออกจากโค้ดก่อน แล้วถ่ายฮีพสแนปชอตใหม่
หากต้องการซ่อนเครื่องมือเก็บ ให้คลิกขวาและเลือกละเว้นเครื่องมือเก็บนี้ เครื่องมือเก็บที่ละเว้นจะมีเครื่องหมาย 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