แก้ปัญหาเกี่ยวกับหน่วยความจำ

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

สรุป

  • ดูว่าหน้าเว็บของคุณใช้หน่วยความจำอยู่มากน้อยเพียงใดด้วยตัวจัดการงานของ Chrome
  • แสดงภาพการใช้งานหน่วยความจำในช่วงเวลาต่างๆ ด้วยการบันทึกไทม์ไลน์
  • ระบุ DOM Tree ที่แยกออกมา (สาเหตุที่พบบ่อยของการรั่วไหลของหน่วยความจำ) ด้วยสแนปชอตฮีป
  • รับการแจ้งเตือนเมื่อมีการจัดสรรหน่วยความจำใหม่ในฮีป JS ด้วยการบันทึกไทม์ไลน์การจัดสรร

ภาพรวม

ตามเจตนาของโมเดลประสิทธิภาพแบบ RAIL จุดมุ่งหมายของการพยายามเพิ่มประสิทธิภาพควรเป็นผู้ใช้

ปัญหาเกี่ยวกับหน่วยความจำเป็นสิ่งสำคัญเนื่องจากผู้ใช้มักจะรับรู้ได้ ผู้ใช้จะทราบถึงปัญหาด้านหน่วยความจำได้ด้วยวิธีต่อไปนี้

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

หน่วยความจำเต็มอิ่ม: "มากเกินไป" แค่ไหน

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

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

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

ตรวจสอบการใช้หน่วยความจำแบบเรียลไทม์ด้วยตัวจัดการงานของ Chrome

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

  1. กด Shift+Esc หรือไปที่เมนูหลักของ Chrome แล้วเลือกเครื่องมือเพิ่มเติม > ตัวจัดการงาน เพื่อ เปิดตัวตัวจัดการงาน

    การเปิดตัวจัดการงาน

  2. คลิกขวาที่ส่วนหัวตารางของตัวจัดการงานและเปิดใช้หน่วยความจำ JavaScript

    การเปิดใช้หน่วยความจำ JS

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

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

แสดงภาพการรั่วไหลของหน่วยความจำด้วยการบันทึกประสิทธิภาพ

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

  1. เปิดแผงประสิทธิภาพในเครื่องมือสำหรับนักพัฒนาเว็บ
  2. เปิดใช้ช่องทำเครื่องหมายหน่วยความจำ
  3. บันทึกเสียง

หากต้องการสาธิตการบันทึกความทรงจำด้านประสิทธิภาพ โปรดดูโค้ดด้านล่าง

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

ทุกครั้งที่มีการกดปุ่มที่อ้างอิงในโค้ด จะมีการเพิ่มโหนด div 10,000 โหนดลงในส่วนเนื้อความของเอกสาร และระบบจะพุชสตริงอักขระ 1 ล้านตัว x ไปยังอาร์เรย์ x การเรียกใช้โค้ดนี้จะสร้างการบันทึกไทม์ไลน์เหมือนกับภาพหน้าจอต่อไปนี้

ตัวอย่างการเติบโตอย่างง่าย

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

ตอนนี้เป็นการวิเคราะห์โค้ดโดยเปรียบเทียบกับภาพหน้าจอ หากคุณดูตัวนับโหนด (กราฟสีเขียว) คุณจะเห็นว่าตัวเลขดังกล่าวตรงกับโค้ดอย่างชัดเจน จำนวนโหนดจะเพิ่มขึ้น ในขั้นตอนที่ไม่ต่อเนื่อง คุณสันนิษฐานได้ว่าการเพิ่มแต่ละครั้งในจำนวนโหนดเป็นการเรียก grow() กราฟฮีป JS (กราฟสีน้ำเงิน) ไม่ได้ตรงไปตรงมามากนัก เพื่อให้เป็นไปตามแนวทางปฏิบัติแนะนำ การดิปแรกคือการบังคับเก็บขยะ (ทำได้โดยกดปุ่มรวบรวมขยะ) ขณะที่การบันทึกดำเนินไป คุณจะเห็นขนาดฮีป JS พุ่งสูงขึ้น การดำเนินการเช่นนี้เป็นเรื่องปกติและคาดหวังว่าโค้ด JavaScript จะสร้างโหนด DOM ทุกครั้งที่คลิกปุ่มและต้องทำงานหนักมากเมื่อสร้างสตริงอักขระ 1 ล้านตัว สิ่งสำคัญในที่นี้คือข้อเท็จจริงที่ว่าฮีพ JS สิ้นสุดอยู่สูงกว่าตอนเริ่มต้น ("จุดเริ่มต้น" ในที่นี้คือจุดหลังจากการบังคับเก็บขยะ) ในโลกแห่งความเป็นจริง หากคุณเห็นรูปแบบการเพิ่มขนาดฮีป JS หรือขนาดโหนดนี้ อาจทำให้หน่วยความจำรั่วไหล

สำรวจการรั่วไหลของหน่วยความจำในแผนผัง DOM ที่ถอดออกด้วยสแนปชอตฮีป

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

ต่อไปนี้เป็นตัวอย่างง่ายๆ ของโหนด DOM ที่ปลดออก

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

การคลิกปุ่มที่อ้างอิงในโค้ดจะสร้างโหนด ul ที่มีรายการย่อย li 10 รายการ โหนดเหล่านี้อ้างอิงตามโค้ดแต่ไม่มีอยู่ในแผนผัง DOM จึงจะถูกถอดออก

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

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

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

สแนปชอตอาจใช้เวลาสักครู่ในการประมวลผลและโหลด เมื่อเสร็จแล้ว ให้เลือกจากแผงด้านซ้าย (ชื่อ HEAP SNAPSHOTS)

พิมพ์ Detached ในช่องข้อความตัวกรองชั้นเรียนเพื่อค้นหา DOM Tree ที่แยกออกมา

การกรองสำหรับโหนดที่ปลดออก

ขยายกะรัตเพื่อสำรวจต้นไม้ที่แยกออกมา

กำลังตรวจสอบต้นไม้ที่ปลดออก

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

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

กำลังตรวจสอบโหนดสีเหลือง

ระบุการรั่วไหลของหน่วยความจำฮีป JS ด้วยไทม์ไลน์การจัดสรร

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

ในการแสดงไทม์ไลน์การจัดสรร ให้พิจารณาใช้โค้ดต่อไปนี้

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

ทุกครั้งที่มีการพุชปุ่มที่อ้างอิงในโค้ด ระบบจะเพิ่มสตริงอักขระ 1 ล้านตัวลงในอาร์เรย์ x

หากต้องการบันทึกไทม์ไลน์การจัดสรร ให้เปิดเครื่องมือสำหรับนักพัฒนาเว็บ ไปที่แผงโปรไฟล์ เลือกปุ่มตัวเลือกบันทึกไทม์ไลน์การจัดสรร กดปุ่มเริ่ม ดำเนินการที่คุณสงสัยว่าทำให้หน่วยความจำรั่วไหล แล้วกดปุ่มหยุดบันทึก (ปุ่มหยุดบันทึก) เมื่อบันทึกเสร็จแล้ว

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

การจัดสรรใหม่

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

ลำดับเวลาการจัดสรรที่ซูม

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

รายละเอียดออบเจ็กต์

ตรวจสอบการจัดสรรหน่วยความจำตามฟังก์ชัน

ใช้ประเภทการสุ่มตัวอย่างการจัดสรรในแผงหน่วยความจำเพื่อดูการจัดสรรหน่วยความจำตามฟังก์ชัน JavaScript

เครื่องมือสร้างโปรไฟล์การจัดสรรระเบียน

  1. เลือกปุ่มตัวเลือกการสุ่มตัวอย่างการจัดสรร หากมีผู้ปฏิบัติงานในหน้านั้น คุณสามารถเลือกผู้ปฏิบัติงานนั้นเป็นเป้าหมายในการสร้างโปรไฟล์ได้โดยใช้เมนูแบบเลื่อนลงข้างปุ่มเริ่มต้น
  2. กดปุ่มเริ่ม
  3. ดำเนินการตามในหน้าเว็บที่คุณต้องการตรวจสอบ
  4. กดปุ่มหยุดเมื่อคุณทำงานทั้งหมดเสร็จแล้ว

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

โปรไฟล์การจัดสรร

ตรวจหาขยะที่สะสมบ่อย

หากหน้าเว็บหยุดชั่วคราวอยู่บ่อยๆ แสดงว่าอาจมีปัญหาเกี่ยวกับการเก็บรวบรวมขยะ

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

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