การจัดการหน่วยความจำอย่างมีประสิทธิภาพในระดับเดียวกับ Gmail

Loreena Lee
Loreena Lee

เกริ่นนำ

แม้ว่า 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 ประเภทดังนี้

  1. หมายเลข (เช่น 4, 3.14159)
  2. บูลีน (จริงหรือเท็จ)
  3. สตริง ("สวัสดีโลก")

ประเภทพื้นฐานเหล่านี้ไม่สามารถอ้างอิงค่าอื่นใดได้ ในกราฟออบเจ็กต์ ค่าเหล่านี้จะเป็น Leaf หรือสิ้นสุดโหนดเสมอ ซึ่งหมายความว่าจะไม่มีขอบขาออก

คอนเทนเนอร์มีประเภทเดียวคือออบเจ็กต์ ใน JavaScript ออบเจ็กต์คืออาร์เรย์ที่เชื่อมโยง ออบเจ็กต์ที่ไม่ว่างเปล่าคือโหนดภายในที่มี Edge ขาออกเป็นค่าอื่น (โหนด)

เกี่ยวกับอาร์เรย์

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

คำศัพท์

  1. ค่า - อินสแตนซ์ของประเภทดั้งเดิม วัตถุ อาร์เรย์ ฯลฯ
  2. ตัวแปร - ชื่อที่อ้างอิงค่า
  3. คุณสมบัติ - ชื่อในออบเจ็กต์ที่อ้างอิงค่า

กราฟวัตถุ

ค่าทั้งหมดใน 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 ส่วนดังต่อไปนี้

  1. jsHeapSizeLimit - จำนวนหน่วยความจำ (หน่วยเป็นไบต์) ที่จำกัดของฮีป JavaScript
  2. totalJSHeapSize - จำนวนหน่วยความจำ (ในหน่วยไบต์) ที่ฮีป JavaScript ได้จัดสรรไว้ รวมถึงพื้นที่ว่าง
  3. 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

เนื่องจาก Gmail ใช้หน่วยความจำน้อยลง เวลาในการตอบสนองของการปิด GC จึงลดลง ซึ่งช่วยเพิ่มประสบการณ์โดยรวมของผู้ใช้

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

คำกระตุ้นให้ดำเนินการ (Call-To-Action)

ถามตัวคุณเองด้วยคำถามต่อไปนี้

  1. แอปของฉันใช้หน่วยความจำมากเพียงใด อาจเป็นไปได้ว่าคุณใช้หน่วยความจำมากเกินไปซึ่งขัดแย้งกับความเชื่อที่ได้รับความนิยมนั้นมีผลเสียสุทธิต่อประสิทธิภาพโดยรวมของแอปพลิเคชัน ไม่ใช่เรื่องง่ายที่จะทราบตัวเลขที่ถูกต้อง แต่ให้ตรวจสอบว่าการแคชหน้าเว็บเพิ่มเติมที่ใช้อยู่จะส่งผลให้เกิดประสิทธิภาพที่วัดได้
  2. หน้าเว็บของฉันไม่รั่วไหลออกไหม หากหน้าเว็บมีหน่วยความจำรั่วไหล จะไม่ส่งผลกระทบต่อประสิทธิภาพของหน้าเว็บ แต่ยังส่งผลต่อแท็บอื่นๆ ด้วย ใช้เครื่องมือติดตามวัตถุเพื่อช่วยจำกัดรอยรั่ว
  3. หน้าเว็บของฉันมี GCing บ่อยแค่ไหน คุณสามารถดูการหยุด GC ชั่วคราวได้โดยใช้แผงไทม์ไลน์ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์ Chrome หากหน้าเว็บของคุณมี GCing บ่อยครั้ง เป็นไปได้ว่าคุณจัดสรรข้อมูลบ่อยเกินไปโดยทำลายความจำของคนรุ่นเยาว์

บทสรุป

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