Javascript มี หน่วยความจำรั่ว หรือไม่? ถ้าเป็นเช่นนั้นจะหลีกเลี่ยงได้อย่างไร? เนื่องจากเมื่อเร็ว ๆ นี้มีคนถามคำถามที่คล้ายกันกับฉันหลายคน ดูเหมือนว่าไม่มีใครศึกษาเนื้อหาส่วนนี้อย่างเป็นระบบ ดังนั้นฉันจึงวางแผนที่จะแบ่งปันข้อมูลบางอย่างที่ฉันรวบรวมเมื่อไม่กี่ปีก่อนกับคุณ
ก่อนอื่น อาจกล่าวได้อย่างมั่นใจว่าวิธีการเขียน JavaScript บางวิธีจะทำให้หน่วยความจำรั่ว อย่างน้อยภายใต้ IE6 ดังนั้น วันนี้เมื่อ IE6 ปฏิเสธที่จะเลิกใช้ เรายังคงต้องเข้าใจความรู้ที่เกี่ยวข้อง (แม้ว่าในกรณีส่วนใหญ่ หน่วยความจำรั่วที่เกิดจาก js ไม่ใช่สาเหตุหลักที่ทำให้คอมพิวเตอร์ทำงานช้าลง) การวิจัยที่เกี่ยวข้องเน้นไปที่ปี 2548-50 เป็นหลัก บทความนี้ไม่มีแนวคิดใหม่ๆ เลย หากคุณมีเพื่อนที่เคยศึกษาเรื่องนี้มาก่อน ก็เพิกเฉยได้
ในฐานะนักพัฒนาส่วนหน้า เมื่อเข้าใจปัญหาเหล่านี้ คุณจำเป็นต้องรู้ว่าปัญหาเหล่านี้คืออะไรและเพราะเหตุใด ดังนั้น ก่อนที่จะแนะนำปัญหาหน่วยความจำรั่วของ js เรามาเริ่มกันที่สาเหตุที่หน่วยความจำรั่ว
เมื่อพูดถึงหน่วยความจำรั่ว เราต้องพูดถึงวิธีการจัดสรรหน่วยความจำ การจัดสรรหน่วยความจำมีสามวิธี ได้แก่:
1. การจัดสรรแบบคงที่: รูปแบบการจัดสรรของตัวแปรคงที่และตัวแปรร่วม หากเรามองห้องเป็นโปรแกรม เราก็อาจคิดว่าหน่วยความจำที่จัดสรรแบบคงที่นั้นเป็นเฟอร์นิเจอร์ที่ทนทานในห้อง โดยปกติแล้ว ไม่จำเป็นต้องปล่อยและรีไซเคิล เพราะไม่มีใครทิ้งตู้เสื้อผ้าออกไปนอกหน้าต่างเหมือนถังขยะทุกวัน
2. การจัดสรรอัตโนมัติ: วิธีการจัดสรรหน่วยความจำสำหรับตัวแปรโลคัลบนสแต็ก หน่วยความจำในสแต็กสามารถถูกปล่อยออกมาโดยอัตโนมัติด้วยการดำเนินการป๊อปเมื่อบล็อกโค้ดออก
คล้ายกับคนที่มาที่ห้องเพื่อทำสิ่งต่างๆ เมื่อทำเสร็จแล้ว พวกเขาจะออกไปเอง และพื้นที่ที่พวกเขาครอบครองจะถูกปล่อยโดยอัตโนมัติเมื่อคนเหล่านี้ออกไป
3. การจัดสรรแบบไดนามิก: วิธีการจัดสรรพื้นที่หน่วยความจำในฮีปแบบไดนามิกเพื่อจัดเก็บข้อมูล นั่นคือหน่วยความจำที่ใช้สำหรับใช้ malloc หรือใหม่ในขณะที่โปรแกรมกำลังทำงานอยู่เราต้องปล่อยมันเองโดยใช้ free หรือ Delete โปรแกรมเมอร์จะกำหนดอายุการใช้งานของหน่วยความจำแบบไดนามิก เมื่อคุณลืมปล่อยมันจะทำให้หน่วยความจำรั่วอย่างหลีกเลี่ยงไม่ได้ ในกรณีนี้หน่วยความจำในกองก็เหมือนกับผ้าเช็ดปากที่เราใช้ทุกวันหลังจากใช้แล้วเราต้องทิ้งลงถังขยะไม่เช่นนั้นบ้านจะเละเทะ ดังนั้นคนขี้เกียจจึงใฝ่ฝันที่จะมีหุ่นยนต์ประจำบ้านมาทำความสะอาดด้วย ในการพัฒนาซอฟต์แวร์ หากคุณขี้เกียจเกินไปที่จะเพิ่มหน่วยความจำ คุณต้องมีโรบ็อตที่คล้ายกัน ซึ่งจริงๆ แล้วคือตัวรวบรวมขยะที่ใช้งานโดยอัลกอริธึมเฉพาะ มันเป็นข้อบกพร่องบางประการในกลไกการรวบรวมขยะนั่นเองที่นำไปสู่การรั่วไหลของหน่วยความจำ JavaScript
เมื่อไม่กี่ปีก่อน ฉันได้อ่านบทความเรื่อง "ประวัติศาสตร์ที่น่าสนใจของการรีไซเคิลขยะ" ซึ่งให้คำอธิบายเชิงลึกเกี่ยวกับกลไกการเก็บขยะ
เช่นเดียวกับเทคโนโลยีซูเปอร์ชาร์จเจอร์ซึ่งเป็นเทคโนโลยีที่ใช้โดยรถยนต์หรูหลายคันเป็นจุดขาย ซึ่งจริงๆ แล้วใช้โดยเมอร์เซเดส-เบนซ์ในช่วงทศวรรษปี 1910 เทคโนโลยีการรีไซเคิลขยะมีมานานแล้ว ภาษา Lisp เกิดที่ MIT ประมาณปี 1960 เป็นภาษาแรกที่อาศัยเทคโนโลยีการจัดสรรหน่วยความจำแบบไดนามิกอย่างมาก ข้อมูลเกือบทั้งหมดใน Lisp ปรากฏในรูปแบบของ "ตาราง" และพื้นที่ที่ครอบครองโดย "ตาราง" อยู่ในฮีป จัดสรรแบบไดนามิก คุณสมบัติการจัดการหน่วยความจำแบบไดนามิกโดยธรรมชาติของภาษา Lisp ต้องการให้นักออกแบบภาษา Lisp แก้ไขปัญหาการปล่อยบล็อกหน่วยความจำแต่ละบล็อกในฮีปโดยอัตโนมัติ (ไม่เช่นนั้นโปรแกรมเมอร์ Lisp จะถูกครอบงำด้วยคำสั่งว่างหรือลบจำนวนนับไม่ถ้วนในโปรแกรมอย่างหลีกเลี่ยงไม่ได้) สิ่งนี้นำไปสู่การกำเนิดและการพัฒนาเทคโนโลยีการเก็บขยะโดยตรง
อัลกอริธึมการรวบรวมขยะขั้นพื้นฐานที่สุดสามประการก็ปรากฏขึ้นพร้อมกันในขณะนั้น มาดูกันทีละเรื่อง:
อัลกอริทึมการนับอ้างอิง: นี่อาจเป็นวิธีแรกที่นึกถึง ถ้าจะเปรียบเปรย การนับอ้างอิงสามารถเข้าใจได้ด้วยวิธีนี้ มีเอกสารสีขาวมากมายในบ้าน และเอกสารเหล่านี้ก็เหมือนกับความทรงจำ การใช้ความทรงจำก็เหมือนกับการเขียนลงบนกระดาษเหล่านี้ หน่วยความจำสามารถใช้ได้ตามใจชอบ แต่มีเงื่อนไข ใครก็ตามที่ใช้กระดาษแผ่นหนึ่งจะต้องเขียนเลข 1 ที่มุมกระดาษ ถ้าคนสองคนใช้กระดาษแผ่นหนึ่งพร้อมกัน การนับจะกลายเป็น 2 และอื่นๆ เมื่อบุคคลใช้กระดาษเสร็จแล้ว จำนวนที่มุมจะต้องลดลง 1 ด้วยวิธีนี้ เมื่อนับกลายเป็น 0 จะเป็นไปตามเงื่อนไขการเก็บขยะ และหุ่นยนต์ที่รออยู่ข้างๆ จะโยนกระดาษลงในถังทันที ขยะ. ตัวรวบรวมขยะแบบเคาน์เตอร์อ้างอิงทำงานเร็วขึ้น ไม่ขัดจังหวะการทำงานของโปรแกรมเป็นเวลานาน และเหมาะสำหรับโปรแกรมที่ต้องรันแบบเรียลไทม์ อย่างไรก็ตาม ตัวนับอ้างอิงจะเพิ่มค่าใช้จ่ายในการรันโปรแกรม ขณะเดียวกัน ก็มีปัญหาใหญ่อีกประการหนึ่งคือมีข้อบกพร่อง นั่นคือ เมื่อสร้างการอ้างอิงแบบวงกลมแล้ว หน่วยความจำจะรั่วไหล ตัวอย่างเช่น เราสร้างวัตถุ a และ b ใหม่ ในเวลานี้ จำนวน a และ b เป็น 1 ทั้งคู่ จากนั้น เราชี้คุณลักษณะของ a ถึง b และคุณลักษณะของ b ในเวลานี้ เนื่องจาก ความสัมพันธ์อ้างอิง จำนวน a และ b ทั้งคู่จะกลายเป็น 2 เมื่อโปรแกรมสิ้นสุดและออกจากขอบเขต โปรแกรมจะลดจำนวน a ลง 1 โดยอัตโนมัติ เนื่องจากจำนวน a ในตอนท้ายยังคงเป็น 1 ดังนั้น a จะไม่เป็น ในทำนองเดียวกัน การนับสุดท้ายของ b ก็คือ 1 เช่นกัน b จะไม่ถูกปล่อยออกมา และหน่วยความจำก็รั่วไหล!