เกริ่นนำ
แม้ว่า JavaScript จะใช้การรวบรวมขยะสำหรับการจัดการหน่วยความจำอัตโนมัติ แต่ก็ไม่ได้มาแทนที่การจัดการหน่วยความจำที่มีประสิทธิภาพในแอปพลิเคชัน แอปพลิเคชัน JavaScript ประสบปัญหาเดียวกับที่แอปพลิเคชันในเครื่องพบ เช่น หน่วยความจำรั่วไหลและการขยายตัว แต่ก็ยังต้องหยุดเก็บขยะชั่วคราวด้วย แอปพลิเคชันขนาดใหญ่อย่าง Gmail พบปัญหาเดียวกับที่พบแอปพลิเคชันขนาดเล็ก อ่านต่อเพื่อดูวิธีที่ทีม Gmail ใช้เครื่องมือสำหรับนักพัฒนาเว็บใน Chrome เพื่อระบุ แยก และแก้ไขปัญหาเกี่ยวกับหน่วยความจำ
เซสชัน Google I/O 2013
เราได้นำเสนอข้อมูลนี้ที่ Google I/O 2013 ดูวิดีโอด้านล่างนี้
Gmail เรามีปัญหา...
ทีม Gmail กำลังประสบปัญหาร้ายแรง เกร็ดเล็กเกร็ดน้อยเกี่ยวกับแท็บ Gmail ที่ใช้หน่วยความจำหลายกิกะไบต์ในแล็ปท็อปและเดสก์ท็อปที่มีทรัพยากรมากถูกได้ยินเข้ามาบ่อยขึ้นเรื่อยๆ โดยมักจะกล่าวถึงข้อสรุปที่จะลดการใช้งานเบราว์เซอร์ทั้งหมด เรื่องราวเกี่ยวกับ CPU ถูกปักหมุดไว้ที่ 100% แอปที่ไม่ตอบสนอง และแท็บเศร้าใน Chrome ("เขาตายแล้ว จิม") ทีมก็เลยไม่รู้ว่าจะเริ่มวินิจฉัยปัญหายังไง ไม่ต้องมาแก้ไขเสียขนาดนั้นเลย พวกเขาไม่ทราบว่าปัญหาเกิดขึ้นในวงกว้างเพียงใด และเครื่องมือที่มีอยู่ก็ไม่สามารถขยายการใช้งานไปยังแอปพลิเคชันขนาดใหญ่ได้ ทีมงานได้ร่วมมือกับทีม Chrome และร่วมกันพัฒนาเทคนิคใหม่ๆ ขึ้นมาเพื่อคัดแยกปัญหาหน่วยความจำ ปรับปรุงเครื่องมือที่มีอยู่เดิม และช่วยให้รวบรวมข้อมูลหน่วยความจำจากการทำงานภาคสนามได้ แต่ก่อนที่จะไปยังเครื่องมือเหล่านี้ มาดูข้อมูลพื้นฐานเกี่ยวกับการจัดการหน่วยความจำของ JavaScript กันก่อน
พื้นฐานการจัดการหน่วยความจำ
ก่อนที่จะจัดการหน่วยความจำใน JavaScript ได้อย่างมีประสิทธิภาพ คุณต้องเข้าใจหลักการพื้นฐาน ส่วนนี้จะพูดถึงประเภทดั้งเดิม กราฟออบเจ็กต์ และให้คำจำกัดความของการเพิ่มขึ้นของหน่วยความจำโดยทั่วไปและการรั่วไหลของหน่วยความจำใน JavaScript หน่วยความจำใน JavaScript สามารถทำให้เกิดแนวคิดเป็นกราฟได้ และทฤษฎีกราฟนี้มีบทบาทในการจัดการหน่วยความจำของ JavaScript และเครื่องมือสร้างโปรไฟล์ฮีป
ประเภทพื้นฐาน
JavaScript มีประเภทพื้นฐาน 3 ประเภทดังนี้
- หมายเลข (เช่น 4, 3.14159)
- บูลีน (จริงหรือเท็จ)
- สตริง ("สวัสดีโลก")
ประเภทพื้นฐานเหล่านี้ไม่สามารถอ้างอิงค่าอื่นใดได้ ในกราฟออบเจ็กต์ ค่าเหล่านี้จะเป็น Leaf หรือสิ้นสุดโหนดเสมอ ซึ่งหมายความว่าจะไม่มีขอบขาออก
คอนเทนเนอร์มีประเภทเดียวคือออบเจ็กต์ ใน JavaScript ออบเจ็กต์คืออาร์เรย์ที่เชื่อมโยง ออบเจ็กต์ที่ไม่ว่างเปล่าคือโหนดภายในที่มี Edge ขาออกเป็นค่าอื่น (โหนด)
เกี่ยวกับอาร์เรย์
อาร์เรย์ใน JavaScript เป็นออบเจ็กต์ที่มีคีย์ตัวเลข ซึ่งเป็นการลดความซับซ้อน เนื่องจากรันไทม์ของ JavaScript จะเพิ่มประสิทธิภาพออบเจ็กต์ที่คล้ายกับอาร์เรย์ และแสดงออบเจ็กต์เหล่านั้นในเบื้องหลังเป็นอาร์เรย์
คำศัพท์
- ค่า - อินสแตนซ์ของประเภทดั้งเดิม วัตถุ อาร์เรย์ ฯลฯ
- ตัวแปร - ชื่อที่อ้างอิงค่า
- คุณสมบัติ - ชื่อในออบเจ็กต์ที่อ้างอิงค่า
กราฟวัตถุ
ค่าทั้งหมดใน JavaScript เป็นส่วนหนึ่งของกราฟออบเจ็กต์ กราฟเริ่มต้นด้วยราก เช่น ออบเจ็กต์หน้าต่าง คุณควบคุมอายุการใช้งานของรูท GC ไม่ได้ เนื่องจากเบราว์เซอร์สร้างขึ้นและถูกทำลายเมื่อยกเลิกการโหลดหน้าเว็บ ตัวแปรร่วมเป็นพร็อพเพอร์ตี้ในหน้าต่าง
เมื่อใดคุณค่าจะกลายเป็นขยะ
ค่าจะกลายเป็นขยะเมื่อไม่มีเส้นทางจากรูทไปยังค่า กล่าวคือ เมื่อเริ่มต้นที่รูทและค้นหาพร็อพเพอร์ตี้ออบเจ็กต์และตัวแปรทั้งหมดที่ยังมีชีวิตอยู่ในสแต็กเฟรมอย่างละเอียด จะทำให้เข้าถึงค่าไม่ได้และจะกลายเป็นขยะ
การรั่วไหลของหน่วยความจำใน JavaScript คืออะไร
การรั่วไหลของหน่วยความจำใน JavaScript เกิดขึ้นบ่อยที่สุดเมื่อมีโหนด DOM ที่ไม่สามารถเข้าถึงจากแผนผัง DOM ของหน้าเว็บ แต่ยังคงอ้างอิงโดยออบเจ็กต์ JavaScript ปัจจุบันเบราว์เซอร์ที่ทันสมัยทำให้การรั่วไหลอย่างไม่ได้ตั้งใจทำได้ยากขึ้น แต่ก็ยังง่ายกว่าที่คิด สมมติว่าคุณเพิ่มองค์ประกอบต่อท้ายโครงสร้าง DOM ดังนี้
email.message = document.createElement("div");
displayList.appendChild(email.message);
ต่อมาคุณนำองค์ประกอบออกจากรายการที่แสดง
displayList.removeAllChildren();
ตราบใดที่มี email
อยู่ ระบบจะไม่นําองค์ประกอบ DOM ที่อ้างอิงโดยข้อความออก แม้ว่าตอนนี้จะถูกตัดออกจากแผนผัง DOM ของหน้าก็ตาม
บลูตคืออะไร
หน้าเว็บมีขนาดใหญ่เมื่อคุณใช้หน่วยความจำเกินกว่าที่จำเป็นเพื่อให้หน้าเว็บมีความเร็วสูงสุด การรั่วไหลของหน่วยความจำโดยอ้อมก็ทำให้เนื้องอกขึ้นมาด้วย แต่นั่นไม่ใช่เพราะการออกแบบ แคชของแอปพลิเคชันที่ไม่มีขอบเขตใดๆ เป็นแหล่งที่มาที่พบได้บ่อยของการขยายหน่วยความจำ นอกจากนี้ หน้าเว็บอาจขยายใหญ่ขึ้นได้ด้วยข้อมูลโฮสต์ เช่น ข้อมูลพิกเซลที่โหลดจากรูปภาพ
บริการเก็บขยะคืออะไร
การเก็บขยะคือวิธีการเรียกคืนหน่วยความจำใน JavaScript โดยเบราว์เซอร์จะตัดสินใจดำเนินการดังกล่าว ระหว่างคอลเล็กชัน การดำเนินการของสคริปต์ทั้งหมดในหน้าเว็บจะถูกระงับ ขณะที่ค่าที่ทำงานอยู่จะค้นพบโดยการข้ามผ่านกราฟออบเจ็กต์ที่เริ่มต้นที่รูท GC ค่าทั้งหมดที่ไม่ติดต่อได้จะได้รับการจัดประเภทเป็นขยะ ตัวจัดการหน่วยความจำเรียกคืนหน่วยความจำสำหรับค่าขยะ
รายละเอียดเกี่ยวกับเครื่องเก็บขยะ V8
เพื่อช่วยคุณทำความเข้าใจเพิ่มเติมเกี่ยวกับการเก็บรวบรวมขยะ เรามาดูรายละเอียดของระบบเก็บขยะ V8 กัน V8 ใช้นักรวบรวมจากรุ่นสู่รุ่น ความทรงจำแบ่งออกเป็น 2 รุ่น คือ คนรุ่นใหม่และคนแก่ การจัดสรรและการเก็บรวบรวมภายในวัยรุ่นเกิดขึ้นอย่างรวดเร็วและบ่อยครั้ง การจัดสรรและการเก็บรวบรวมภายในเวอร์ชันเก่าช้าลงและเกิดขึ้นไม่บ่อยนัก
นักสะสมรุ่นย่อย
V8 ใช้คอลเลกชัน 2 รุ่น อายุของค่าจะกําหนดเป็นจำนวนไบต์ที่จัดสรรนับตั้งแต่ที่มีการจัดสรร ในทางปฏิบัติ อายุของค่าหนึ่งๆ มักจะประมาณจากจำนวนคอลเล็กชันของคนรุ่นใหม่ที่รอดชีวิต หลังจากค่านั้นเก่าพอสมควรแล้ว ค่านั้นก็มีอายุอยู่ในรุ่นเดิม
ในทางปฏิบัติ ค่าที่จัดสรรใหม่จะใช้งานได้ไม่นาน การศึกษาโปรแกรม SmallTalk แสดงให้เห็นว่าคุณค่านิยมเพียง 7% ที่มีผลต่อชีวิตหลังจากคนรุ่นใหม่ การศึกษาที่คล้ายกันในรันไทม์นี้พบว่า โดยเฉลี่ยระหว่าง 90% ถึง 70% ของค่าที่จัดสรรใหม่ไม่เคยมีอยู่ในยุคเก่า
เด็กรุ่นใหม่
ฮีปรุ่นใหม่ใน V8 แบ่งออกเป็น 2 เว้นวรรค โดยตั้งชื่อตามและไปยัง ระบบจะจัดสรรหน่วยความจำจากไปยังพื้นที่ทำงาน การจัดสรรทำได้เร็วมากจนกระทั่งถึงพื้นที่ว่างในจุดที่มีการเรียกคอลเล็กชันคนรุ่นใหม่ คอลเล็กชันคนหนุ่มสาวสลับจากและไปยังพื้นที่ก่อน จากนั้นระบบจะสแกนเก่าเป็นอวกาศ (ปัจจุบันจากอวกาศ) และคัดลอกค่าแบบเรียลไทม์ทั้งหมดไปยังอวกาศหรือคงไว้ให้กับคนรุ่นใหม่ คอลเล็กชันเด็กรุ่นใหม่ทั่วไปจะใช้เวลาตามลำดับ 10 มิลลิวินาที (ms)
โดยธรรมชาติแล้ว คุณควรเข้าใจว่าการจัดสรรแต่ละครั้งที่แอปพลิเคชันทำจะทำให้คุณใช้พื้นที่ใกล้เกินไปและทำให้ GC หยุดชั่วคราว นักพัฒนาแอปเกมควรคำนึงถึงเวลาเฟรมที่ 16 มิลลิวินาที (จำเป็นเพื่อให้ได้ 60 เฟรมต่อวินาที) แอปพลิเคชันจะต้องไม่มีการจัดสรร เนื่องจากคอลเล็กชันรุ่นใหม่เพียงคอลเล็กชันเดียวจะกินเวลาเฟรมเกือบทั้งหมด
รุ่นเดิม
ฮีปรุ่นเก่าใน V8 ใช้อัลกอริทึมคอมแพ็คท์สำหรับคอลเล็กชัน การจัดสรรคนรุ่นใหม่เกิดขึ้นเมื่อใดก็ตามที่ค่านิยมมาจากคนรุ่นใหม่ไปจนถึงคนรุ่นใหม่ เมื่อใดก็ตามที่มีคอลเล็กชันรุ่นเก่า คอลเล็กชันของคนรุ่นใหม่ก็จะเสร็จสมบูรณ์เช่นกัน แอปพลิเคชันของคุณจะหยุดชั่วคราวตามลำดับวินาที ในทางปฏิบัติ สิ่งนี้ยอมรับได้เพราะจะไม่มีคอลเล็กชันภาพเก่าๆ
ข้อมูลสรุปของ V8 GC
การจัดการหน่วยความจำอัตโนมัติด้วยฟังก์ชันการรวบรวมขยะจะช่วยเพิ่มประสิทธิภาพการทำงานของนักพัฒนาซอฟต์แวร์ได้เป็นอย่างดี แต่ทุกครั้งที่คุณจัดสรรค่า จะเป็นการเข้าใกล้การหยุดเก็บขยะชั่วคราวมากขึ้นไปอีก การหยุดเก็บขยะชั่วคราวอาจทำลายความรู้สึกของแอปพลิเคชันด้วยการเปิดใช้งานการรบกวน เมื่อเข้าใจวิธีที่ JavaScript จัดการหน่วยความจำแล้ว คุณก็สามารถเลือกตัวเลือกที่เหมาะสมสำหรับแอปพลิเคชันของคุณได้
การแก้ไข Gmail
ในช่วงปีที่ผ่านมา หลายฟีเจอร์และการแก้ไขข้อบกพร่องได้เข้ามาอยู่ในเครื่องมือสําหรับนักพัฒนาเว็บใน Chrome ทําให้มีประสิทธิภาพมากขึ้นกว่าที่เคย นอกจากนี้ ตัวเบราว์เซอร์เองยังได้ทำการเปลี่ยนแปลงสำคัญใน performance.memory API อีกด้วย ทำให้ Gmail และแอปพลิเคชันอื่นๆ สามารถรวบรวมสถิติของหน่วยความจําจากพื้นที่เก็บข้อมูลได้ เมื่อมีเครื่องมือที่ยอดเยี่ยมเหล่านี้แล้ว สิ่งที่เคยดูเหมือนทำได้ยากยิ่งกลายเป็นเกมที่น่าตื่นเต้นสำหรับการติดตามผู้ก่อเหตุ
เครื่องมือและเทคนิค
ข้อมูลช่องและ performance.memory API
ตั้งแต่ Chrome 22 เป็นต้นไป performance.memory API จะเปิดใช้โดยค่าเริ่มต้น สำหรับแอปพลิเคชันที่ทำงานเป็นเวลานานอย่าง Gmail ข้อมูลจากผู้ใช้จริงนั้นมีคุณค่าอย่างมาก ข้อมูลนี้ช่วยให้เราแยกแยะระหว่างผู้ใช้ขั้นสูง ผู้ที่ใช้ Gmail วันละ 8-16 ชั่วโมง และได้รับข้อความเป็นร้อยๆ ข้อความต่อวัน จากผู้ใช้ทั่วไปที่ใช้เวลาวันละไม่กี่นาทีใน Gmail ได้รับข้อความหลายสิบข้อความต่อสัปดาห์
API นี้จะแสดงข้อมูล 3 ส่วนดังต่อไปนี้
- jsHeapSizeLimit - จำนวนหน่วยความจำ (หน่วยเป็นไบต์) ที่จำกัดของฮีป JavaScript
- totalJSHeapSize - จำนวนหน่วยความจำ (ในหน่วยไบต์) ที่ฮีป JavaScript ได้จัดสรรไว้ รวมถึงพื้นที่ว่าง
- usedJSHeapSize - จำนวนหน่วยความจำ (ในหน่วยไบต์) ที่ใช้อยู่
สิ่งหนึ่งที่ควรทราบไว้คือ API จะแสดงผลค่าหน่วยความจำสำหรับกระบวนการทั้งหมดของ Chrome แม้จะไม่ใช่โหมดเริ่มต้น แต่ในบางกรณี Chrome อาจเปิดแท็บหลายแท็บในกระบวนการแสดงผลเดียวกัน ซึ่งหมายความว่าค่าที่แสดงผลโดย performance.memory อาจมีฟุตพริ้นท์ของหน่วยความจําของแท็บเบราว์เซอร์อื่นๆ นอกเหนือจากแท็บที่มีแอปของคุณ
การวัดหน่วยความจำจำนวนมาก
Gmail ติดตั้งระบบ JavaScript ของตนให้ใช้ performance.memory API ในการรวบรวมข้อมูลหน่วยความจําประมาณ 1 ครั้งทุก 30 นาที เนื่องจากผู้ใช้ Gmail จำนวนมากออกจากแอปครั้งละวัน ทีมจึงสามารถติดตามการเพิ่มขึ้นของหน่วยความจำเมื่อเวลาผ่านไปและสถิติการใช้หน่วยความจำโดยรวม หลังจากที่มีการใช้ Gmail เพื่อรวบรวมข้อมูลหน่วยความจำจากการสุ่มผู้ใช้เพียง 2-3 วัน ทีมมีข้อมูลเพียงพอที่จะทำให้เข้าใจว่าปัญหาหน่วยความจำแพร่หลายเพียงใดในกลุ่มผู้ใช้ทั่วไป การกำหนดเกณฑ์พื้นฐานและใช้สตรีมข้อมูลขาเข้าเพื่อติดตามความคืบหน้าของเป้าหมายในการลดการใช้หน่วยความจำ ท้ายที่สุดแล้ว ข้อมูลนี้ก็จะใช้ในการตรวจจับการถดถอยของหน่วยความจำด้วยเช่นกัน
นอกเหนือจากวัตถุประสงค์ด้านการติดตามแล้ว การวัดภาคสนามยังให้ข้อมูลเชิงลึกที่เจาะลึกเกี่ยวกับความสัมพันธ์ระหว่างการใช้งานหน่วยความจำกับประสิทธิภาพของแอปพลิเคชัน ทีม Gmail พบว่ายิ่งใช้หน่วยความจำมากขึ้นเท่าใด เวลาในการตอบสนองที่ยาวก็จะยิ่งนานขึ้นต่อการดำเนินการทั่วไปของ Gmail ในทางตรงข้ามกับความเชื่อที่ว่า "หน่วยความจำที่มากขึ้นจะทำให้ประสิทธิภาพดีขึ้น" การค้นพบครั้งนี้ทำให้ครีเอเตอร์ได้กระตุ้นเตือนตัวเองให้กลับมาฟังเพลงจำพวกนี้มากกว่าที่เคย
ระบุปัญหาเกี่ยวกับหน่วยความจำด้วยไทม์ไลน์เครื่องมือสำหรับนักพัฒนาเว็บ
ขั้นตอนแรกในการแก้ปัญหาด้านประสิทธิภาพคือการพิสูจน์ว่ามีปัญหานั้นอยู่ สร้างการทดสอบที่สามารถทำซ้ำได้ และทำการวัดพื้นฐานของปัญหา หากไม่มีโปรแกรมที่สามารถทำซ้ำได้ คุณจะไม่สามารถวัดปัญหาได้อย่างน่าเชื่อถือ หากไม่มีการวัดผลพื้นฐาน คุณจะไม่ทราบประสิทธิภาพที่เพิ่มขึ้นมาเท่าใด
แผงไทม์ไลน์ของเครื่องมือสำหรับนักพัฒนาเว็บเป็นตัวเลือกที่เหมาะอย่างยิ่งในการพิสูจน์ว่าปัญหามีอยู่ ซึ่งจะให้ภาพรวมที่สมบูรณ์ของตำแหน่งที่ใช้ไปกับการโหลดและโต้ตอบกับเว็บแอปหรือหน้าเว็บของคุณ เหตุการณ์ทั้งหมดตั้งแต่การโหลดทรัพยากรไปจนถึงการแยกวิเคราะห์ JavaScript การคำนวณรูปแบบ การหยุดเก็บข้อมูลขยะชั่วคราว และการทาสีซ้ำจะถูกพล็อตบนไทม์ไลน์ สำหรับการตรวจสอบปัญหาเกี่ยวกับหน่วยความจำ แผงไทม์ไลน์ยังมีโหมดหน่วยความจำซึ่งติดตามหน่วยความจำที่จัดสรรทั้งหมด จำนวนโหนด DOM จำนวนออบเจ็กต์หน้าต่าง และจำนวน Listener เหตุการณ์ที่จัดสรรไว้
การพิสูจน์ว่ามีปัญหาอยู่
เริ่มด้วยการระบุลำดับการดำเนินการที่คุณสงสัยว่าจะหน่วยความจำรั่วไหล เริ่มบันทึกไทม์ไลน์และดำเนินการตามลำดับการดำเนินการ ใช้ปุ่มถังขยะด้านล่างเพื่อบังคับให้เก็บรวบรวมขยะทั้งหมด หากหลังจากการทำซ้ำ 2-3 ครั้ง คุณเห็นกราฟรูปเขี้ยว แสดงว่าคุณจัดสรรวัตถุที่มีอายุยืนไม่นานอยู่มากมาย แต่หากไม่คาดหวังว่าลำดับการดำเนินการจะทำให้เกิดหน่วยความจำเก็บไว้ และจำนวนโหนด DOM ไม่ได้ลดลงกลับไปเป็นเกณฑ์พื้นฐานที่คุณเริ่มต้น คุณก็มีเหตุผลที่สมควรสงสัยว่ามีการรั่วไหล
เมื่อตรวจสอบแล้วว่าปัญหามีอยู่จริง คุณสามารถขอความช่วยเหลือในการระบุต้นเหตุของปัญหาได้โดยใช้เครื่องมือสร้างโปรไฟล์ฮีปของ DevTools
การค้นหาจุดรั่วของหน่วยความจำด้วยเครื่องมือสร้างโปรไฟล์ฮีปของเครื่องมือสำหรับนักพัฒนาเว็บ
แผงเครื่องมือสร้างโปรไฟล์จะมีทั้งเครื่องมือสร้างโปรไฟล์ CPU และเครื่องมือสร้างโปรไฟล์ฮีป การทำโปรไฟล์ฮีปทำงานด้วยการบันทึกสแนปชอตของกราฟออบเจ็กต์ คนรุ่นเยาว์และคนวัยหนุ่มสาวจะถูกเก็บขยะไปก่อนที่จะถ่ายภาพให้เห็น กล่าวคือ คุณจะเห็นเฉพาะค่าที่ยังไม่หมดอายุเมื่อถ่ายสแนปชอต
ในเครื่องมือสร้างโปรไฟล์ฮีปมีฟังก์ชันมากเกินไปที่จะกล่าวถึงได้อย่างเพียงพอในบทความนี้ แต่คุณสามารถดูเอกสารโดยละเอียดได้ในเว็บไซต์ของนักพัฒนาซอฟต์แวร์ Chrome เราจะเน้นที่เครื่องมือสร้างโปรไฟล์การจัดสรรฮีป
การใช้เครื่องมือสร้างโปรไฟล์การจัดสรรฮีป
เครื่องมือสร้างโปรไฟล์การจัดสรรฮีปจะรวมข้อมูลสแนปชอตโดยละเอียดของเครื่องมือสร้างโปรไฟล์ฮีปเข้ากับการอัปเดตและการติดตามที่เพิ่มขึ้นของแผงไทม์ไลน์ เปิดแผงโปรไฟล์ เริ่มต้นโปรไฟล์ บันทึกการจัดสรรฮีป ดำเนินการตามลำดับ จากนั้นหยุดการบันทึกเพื่อการวิเคราะห์ เครื่องมือสร้างโปรไฟล์การจัดสรรจะบันทึกสแนปชอตของฮีปเป็นระยะๆ ตลอดการบันทึก (ทุกๆ 50 มิลลิวินาที!) และสแนปชอตสุดท้ายอีกรายการในตอนท้ายของการบันทึก
แถบที่ด้านบนจะระบุเวลาที่พบวัตถุใหม่ในฮีป ความสูงของแต่ละแท่งจะสอดคล้องกับขนาดของวัตถุที่จัดสรรล่าสุด และสีของแท่งจะระบุว่าวัตถุเหล่านั้นยังคงอยู่ในสแนปชอตฮีปสุดท้ายหรือไม่ แถบสีน้ำเงินหมายถึงวัตถุที่ยังคงอยู่ในส่วนท้ายของไทม์ไลน์ แถบสีเทาหมายถึงวัตถุที่จัดสรรในระหว่างไทม์ไลน์ แต่นับแต่นั้นมาเก็บรวบรวมขยะ
ในตัวอย่างข้างต้น มีการดำเนินการ 10 ครั้ง โปรแกรมตัวอย่างจะแคชออบเจ็กต์ 5 รายการ ดังนั้นจึงมีแถบสีน้ำเงิน 5 แถบสุดท้าย แต่แถบสีน้ำเงินด้านซ้ายสุดหมายถึงปัญหาที่อาจเกิดขึ้น จากนั้นคุณสามารถใช้แถบเลื่อนในไทม์ไลน์ด้านบนเพื่อซูมเข้าสแนปชอตที่เจาะจงและดูวัตถุที่มีการจัดสรร ณ จุดนั้นเมื่อเร็วๆ นี้ การคลิกออบเจ็กต์ที่ต้องการในฮีปจะแสดงโครงสร้างที่คงไว้ในส่วนล่างของสแนปชอตฮีป การตรวจสอบเส้นทางการเก็บรักษาไปยังออบเจ็กต์ควรให้ข้อมูลที่เพียงพอแก่คุณในการทําความเข้าใจสาเหตุที่ไม่มีการรวบรวมออบเจ็กต์ และคุณสามารถเปลี่ยนโค้ดที่จําเป็นได้เพื่อนำการอ้างอิงที่ไม่จำเป็นออก
การแก้ปัญหาวิกฤติหน่วยความจำของ Gmail
การใช้เครื่องมือและเทคนิคที่กล่าวถึงข้างต้นทำให้ทีม Gmail สามารถระบุข้อบกพร่องได้ 2-3 หมวดหมู่ ได้แก่ แคชที่ไม่มีขอบเขต การเรียกกลับที่มีจำนวนมากขึ้นเรื่อยๆ รอให้เกิดบางสิ่งแต่ไม่เคยเกิดขึ้นจริง และผู้ฟังเหตุการณ์รักษาเป้าหมายของตนไว้โดยไม่ได้ตั้งใจ เมื่อแก้ไขปัญหาเหล่านี้ การใช้งานหน่วยความจำโดยรวมของ Gmail ลดลงอย่างมาก ผู้ใช้ใน 99% ใช้หน่วยความจำน้อยกว่าเดิม 80% และการใช้หน่วยความจำของผู้ใช้ตามค่ามัธยฐานลดลงเกือบ 50%
เนื่องจาก Gmail ใช้หน่วยความจำน้อยลง เวลาในการตอบสนองของการปิด GC จึงลดลง ซึ่งช่วยเพิ่มประสบการณ์โดยรวมของผู้ใช้
นอกจากนี้ ด้วยเหตุที่ทีม Gmail ได้รวบรวมสถิติการใช้หน่วยความจำ ทีมก็ค้นพบปัญหาการถดถอยหลังขยะใน Chrome ได้ด้วย กล่าวอย่างเจาะจงคือ เราพบข้อบกพร่อง 2 อย่างในการแยกส่วนเมื่อข้อมูลหน่วยความจำของ Gmail เริ่มแสดงช่องว่างระหว่างหน่วยความจำทั้งหมดที่จัดสรรกับหน่วยความจำแบบสดเพิ่มขึ้นอย่างมาก
คำกระตุ้นให้ดำเนินการ (Call-To-Action)
ถามตัวคุณเองด้วยคำถามต่อไปนี้
- แอปของฉันใช้หน่วยความจำมากเพียงใด อาจเป็นไปได้ว่าคุณใช้หน่วยความจำมากเกินไปซึ่งขัดแย้งกับความเชื่อที่ได้รับความนิยมนั้นมีผลเสียสุทธิต่อประสิทธิภาพโดยรวมของแอปพลิเคชัน ไม่ใช่เรื่องง่ายที่จะทราบตัวเลขที่ถูกต้อง แต่ให้ตรวจสอบว่าการแคชหน้าเว็บเพิ่มเติมที่ใช้อยู่จะส่งผลให้เกิดประสิทธิภาพที่วัดได้
- หน้าเว็บของฉันไม่รั่วไหลออกไหม หากหน้าเว็บมีหน่วยความจำรั่วไหล จะไม่ส่งผลกระทบต่อประสิทธิภาพของหน้าเว็บ แต่ยังส่งผลต่อแท็บอื่นๆ ด้วย ใช้เครื่องมือติดตามวัตถุเพื่อช่วยจำกัดรอยรั่ว
- หน้าเว็บของฉันมี GCing บ่อยแค่ไหน คุณสามารถดูการหยุด GC ชั่วคราวได้โดยใช้แผงไทม์ไลน์ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ Chrome หากหน้าเว็บของคุณมี GCing บ่อยครั้ง เป็นไปได้ว่าคุณจัดสรรข้อมูลบ่อยเกินไปโดยทำลายความจำของคนรุ่นเยาว์
บทสรุป
เราเริ่มต้นจากวิกฤต ครอบคลุมพื้นฐานหลักของการจัดการหน่วยความจำใน JavaScript และ V8 โดยเฉพาะ คุณได้เรียนรู้วิธีใช้เครื่องมือต่างๆ รวมถึงฟีเจอร์เครื่องมือติดตามออบเจ็กต์ใหม่ที่มีอยู่ใน Chrome บิลด์ล่าสุดแล้ว ทีม Gmail ที่มีความรู้นี้แก้ปัญหาการใช้งานหน่วยความจำและเห็นประสิทธิภาพที่ดีขึ้น คุณก็ทำแบบเดียวกันนี้ได้กับเว็บแอป