คอลเล็กชันขยะ JavaScript คืออะไร สิ่งสำคัญสำหรับผู้เขียนโปรแกรมเว็บคือต้องเข้าใจเกี่ยวกับการรวบรวมขยะ JavaScript เพื่อที่จะเขียนโค้ดที่ดีกว่า
คอลเล็กชันขยะ JavaScript คืออะไร สิ่งสำคัญสำหรับผู้เขียนโปรแกรมเว็บคือต้องเข้าใจเกี่ยวกับการรวบรวมขยะ JavaScript เพื่อที่จะเขียนโค้ดที่ดีกว่า
คำตอบ:
Eric Lippert เขียนโพสต์บล็อกที่มีรายละเอียดเกี่ยวกับเรื่องนี้มาระยะหนึ่งแล้ว (เปรียบเทียบเพิ่มเติมกับVBScript ) อย่างแม่นยำยิ่งขึ้นเขาเขียนเกี่ยวกับJScriptซึ่งเป็นการนำ ECMAScript ไปใช้ของ Microsoft แม้ว่าจะคล้ายกันมากกับ JavaScript ฉันคิดว่าคุณสามารถสันนิษฐานได้ว่าพฤติกรรมส่วนใหญ่จะเหมือนกันสำหรับเอนจิ้น JavaScript ของ Internet Explorer แน่นอนการใช้งานจะแตกต่างกันไปจากเบราว์เซอร์เบราว์เซอร์ แต่ฉันคิดว่าคุณสามารถใช้หลักการทั่วไปจำนวนหนึ่งและนำไปใช้กับเบราว์เซอร์อื่น ๆ
อ้างจากหน้านั้น:
JScript ใช้ตัวรวบรวมขยะที่ไม่ใช่เครื่องหมายและกวาด มันทำงานได้เช่นนี้:
ตัวแปรทุกตัวที่ "อยู่ในขอบเขต" เรียกว่า "เกมกินขยะ" คนเก็บขยะอาจอ้างถึงจำนวนวัตถุสตริงหรืออะไรก็ได้ เราเก็บรายชื่อของคนเก็บขยะ - ตัวแปรจะถูกย้ายไปยังรายการของคนเก็บขยะเมื่อพวกเขาเข้ามาในขอบเขตและออกจากรายการขยะเมื่อพวกเขาออกจากขอบเขต
ทุก ๆ ครั้งที่ตัวรวบรวมขยะจะทำงาน ก่อนอื่นให้วาง "เครื่องหมาย" ไว้ในทุกวัตถุตัวแปรสตริง ฯลฯ - หน่วยความจำทั้งหมดที่ติดตามโดย GC (JScript ใช้โครงสร้างข้อมูลที่หลากหลายภายในและมีบิตที่ไม่ได้ใช้เป็นจำนวนมากในโครงสร้างนั้นดังนั้นเราเพิ่งตั้งหนึ่งในนั้น)
ประการที่สองมันล้างเครื่องหมายบนสัตว์กินของเน่าและการปิด transitive ของการอ้างอิงของคนเก็บขยะ ดังนั้นหากวัตถุที่เก็บขยะอ้างถึงวัตถุที่ไม่ได้ใช้งานเราก็จะทำการล้างบิตบนอุปกรณ์ที่ไม่ได้ใช้งานและทุกอย่างที่มันอ้างถึง (ฉันใช้คำว่า "การปิด" ในแง่ที่ต่างจากโพสต์ก่อนหน้าของฉัน)
ณ จุดนี้เรารู้ว่าหน่วยความจำทั้งหมดที่ทำเครื่องหมายไว้ยังถูกจัดสรรหน่วยความจำซึ่งไม่สามารถเข้าถึงได้โดยเส้นทางใด ๆ จากตัวแปรใด ๆ ในขอบเขต วัตถุเหล่านั้นทั้งหมดได้รับคำสั่งให้ทำลายตัวเองซึ่งทำลายการอ้างอิงแบบวงกลมใด ๆ
วัตถุประสงค์หลักของการรวบรวมขยะคือเพื่อให้โปรแกรมเมอร์ไม่ต้องกังวลเกี่ยวกับการจัดการหน่วยความจำของวัตถุที่พวกเขาสร้างและใช้งาน แต่แน่นอนว่าไม่มีการหลีกเลี่ยงบางครั้ง - มันเป็นประโยชน์เสมอที่จะมีความคิดคร่าวๆ .
บันทึกประวัติ:การแก้ไขคำตอบก่อนหน้านี้มีการอ้างอิงที่ไม่ถูกต้องไปยังdelete
ผู้ประกอบการ ใน JavaScript ประกอบการเอาทรัพย์สินจากวัตถุและเป็นเครือที่แตกต่างกันไปใน C / C ++delete
delete
delete
อย่างไม่ถูกต้อง เช่นในตัวอย่างแรกแทนที่จะเป็นdelete foo
คุณควรลบตัวฟังเหตุการณ์ออกก่อนwindow.removeEventListener()
แล้วจึงใช้foo = null
เพื่อเขียนทับตัวแปร ใน IE delete window.foo
(แต่ไม่ใช่delete foo
) ก็จะได้ผลเช่นกันถ้าfoo
เป็นโลก แต่ถึงอย่างนั้นมันก็ไม่ได้อยู่ใน FF หรือ Opera
delete
เป็นผู้ดำเนินเอก (การแสดงออก) ไม่ใช่คำสั่ง (เช่น: delete 0, delete 0, delete 3
) ดูเหมือนว่าคำสั่งเมื่อแสดงออกโดยคำสั่งการแสดงออก
ระวังการอ้างอิงแบบวงกลมเมื่อเกี่ยวข้องกับวัตถุ DOM:
รูปแบบการรั่วไหลของหน่วยความจำใน JavaScript
โปรดจำไว้ว่าหน่วยความจำสามารถเรียกคืนได้เฉพาะเมื่อไม่มีการอ้างอิงที่ใช้งานกับวัตถุ นี่เป็นข้อผิดพลาดทั่วไปที่มีการปิดและตัวจัดการเหตุการณ์เนื่องจากเอ็นจิน JS บางตัวจะไม่ตรวจสอบว่าตัวแปรใดที่ถูกอ้างอิงจริงในฟังก์ชั่นด้านในและเพียงแค่เก็บตัวแปรท้องถิ่นทั้งหมดของฟังก์ชั่นการปิดล้อม
นี่คือตัวอย่างง่ายๆ:
function init() {
var bigString = new Array(1000).join('xxx');
var foo = document.getElementById('foo');
foo.onclick = function() {
// this might create a closure over `bigString`,
// even if `bigString` isn't referenced anywhere!
};
}
การปรับใช้ JS ที่ไร้เดียงสาไม่สามารถรวบรวมได้bigString
ตราบใดที่ตัวจัดการเหตุการณ์อยู่ใกล้ มีหลายวิธีในการแก้ปัญหานี้เช่นการตั้งค่าbigString = null
ที่ส่วนท้ายของinit()
( delete
จะไม่ทำงานกับตัวแปรโลคัลและอาร์กิวเมนต์ของฟังก์ชัน: delete
ลบคุณสมบัติออกจากวัตถุและวัตถุตัวแปรไม่สามารถเข้าถึงได้ - ES5 ในโหมดเข้มงวดจะทำให้ReferenceError
คุณลอง เพื่อลบตัวแปรโลคอล!)
ฉันแนะนำให้หลีกเลี่ยงการปิดที่ไม่จำเป็นให้มากที่สุดถ้าคุณใส่ใจกับการใช้หน่วยความจำ
คำพูดที่ดีนำมาจากบล็อก
องค์ประกอบ DOM คือ "ขยะที่เก็บรวบรวม" เช่นเดียวกับองค์ประกอบ JScript ซึ่งหมายความว่าหากคุณสร้างวัตถุภายในองค์ประกอบใดส่วนประกอบหนึ่งแล้วสูญเสียการติดตามวัตถุนั้นในที่สุดมันก็จะถูกกำจัด
ตัวอย่างเช่น:
function makeABigObject() {
var bigArray = new Array(20000);
}
เมื่อคุณเรียกใช้ฟังก์ชันนั้นคอมโพเนนต์ JScript จะสร้างวัตถุ (ชื่อ bigArray) ที่สามารถเข้าถึงได้ภายในฟังก์ชัน แต่ทันทีที่ฟังก์ชั่นกลับมาคุณจะ "สูญเสียการติดตาม" ของ bigArray เพราะไม่มีวิธีการอ้างอิงอีกต่อไป ส่วนประกอบ JScript ตระหนักดีว่าคุณไม่ได้ติดตามมันและดังนั้น bigArray จึงถูกล้างออก - หน่วยความจำของมันถูกเรียกคืน สิ่งของชนิดเดียวกันนั้นใช้งานได้ในคอมโพเนนต์ DOM ถ้าคุณพูดdocument.createElement('div')
หรืออะไรทำนองนั้นองค์ประกอบ DOM จะสร้างวัตถุให้คุณ เมื่อคุณสูญเสียการติดตามวัตถุนั้นองค์ประกอบ DOM จะล้างข้อมูลที่เกี่ยวข้อง
เพื่อความรู้ของฉันที่ดีที่สุดวัตถุของ JavaScript จะถูกเก็บรวบรวมขยะเป็นระยะเมื่อไม่มีการอ้างอิงถึงวัตถุ มันเป็นสิ่งที่เกิดขึ้นโดยอัตโนมัติ แต่ถ้าคุณต้องการดูเพิ่มเติมเกี่ยวกับวิธีการทำงานในระดับ C ++ มันสมเหตุสมผลที่จะดูซอร์สโค้ดWebKitหรือV8
โดยทั่วไปแล้วคุณไม่จำเป็นต้องคิดเกี่ยวกับเรื่องนี้อย่างไรก็ตามในเบราว์เซอร์รุ่นเก่าเช่น IE 5.5 และ IE 6 รุ่นก่อนหน้าและรุ่นปัจจุบันการปิดจะสร้างการอ้างอิงแบบวงกลมที่เมื่อไม่ได้เลือกจะสิ้นสุดการกินหน่วยความจำ ในกรณีเฉพาะที่ฉันหมายถึงเกี่ยวกับการปิดเป็นเมื่อคุณเพิ่มการอ้างอิง JavaScript ไปยังวัตถุ dom และวัตถุไปยังวัตถุ DOM ที่อ้างถึงกลับไปที่วัตถุ JavaScript โดยทั่วไปจะไม่สามารถรวบรวมได้และในที่สุดจะทำให้ระบบปฏิบัติการไม่เสถียรในการทดสอบแอพที่วนลูปเพื่อสร้างข้อขัดข้อง ในทางปฏิบัติการรั่วไหลเหล่านี้มักจะมีขนาดเล็ก แต่เพื่อให้โค้ดของคุณสะอาดคุณควรลบการอ้างอิง JavaScript ไปยังวัตถุ DOM
โดยปกติแล้วควรใช้คำหลักลบเพื่อยกเลิกการอ้างอิงวัตถุขนาดใหญ่เช่นข้อมูล JSON ที่คุณได้รับกลับมาและทำสิ่งที่คุณต้องทำโดยเฉพาะในการพัฒนาเว็บบนมือถือ นี่ทำให้การกวาดครั้งต่อไปของ GC เพื่อลบวัตถุนั้นออกและเพิ่มหน่วยความจำ
mark-and-sweep
ขั้นตอนวิธีการรูปแบบการดูแลนี้
garbage collection (GC) เป็นรูปแบบของการจัดการหน่วยความจำอัตโนมัติโดยการลบวัตถุที่ไม่ต้องการอีกต่อไป
กระบวนการใด ๆ ที่จัดการกับหน่วยความจำทำตามขั้นตอนเหล่านี้:
1 - จัดสรรพื้นที่หน่วยความจำของคุณที่คุณต้องการ
2 - ทำการประมวลผลบางอย่าง
3 - เพิ่มพื้นที่หน่วยความจำฟรี
มีสองอัลกอริทึมหลักที่ใช้ในการตรวจจับวัตถุที่ไม่ต้องการอีกต่อไป
การรวบรวมขยะนับอ้างอิง : อัลกอริทึมนี้ช่วยลดคำจำกัดความของ "วัตถุไม่จำเป็นอีกต่อไป" เป็น "วัตถุไม่มีวัตถุอื่นที่อ้างอิงถึง" วัตถุจะถูกลบหากไม่มีการอ้างอิงชี้ไปที่มัน
อัลกอริธึม Mark-and-sweep : เชื่อมต่อแต่ละวัตถุกับแหล่งที่มา วัตถุใด ๆ ไม่เชื่อมต่อกับรูทหรือวัตถุอื่น วัตถุนี้จะถูกลบออก
เบราว์เซอร์ที่ทันสมัยที่สุดในปัจจุบันโดยใช้อัลกอริทึมที่สอง
"ในวิทยาการคอมพิวเตอร์การรวบรวมขยะ (GC) เป็นรูปแบบหนึ่งของการจัดการหน่วยความจำอัตโนมัติตัวรวบรวมขยะหรือเพียงตัวรวบรวมพยายามเรียกคืนขยะหรือหน่วยความจำที่ใช้โดยวัตถุที่จะไม่สามารถเข้าถึงหรือกลายพันธุ์อีกครั้งโดยแอปพลิเคชัน"
เอ็นจิ้น JavaScript ทั้งหมดมีตัวรวบรวมขยะของตัวเองและอาจแตกต่างกัน เวลาส่วนใหญ่คุณไม่ต้องจัดการกับพวกเขาเพราะพวกเขาเพียงแค่ทำในสิ่งที่พวกเขาควรจะทำ
การเขียนโค้ดที่ดีขึ้นส่วนใหญ่ขึ้นอยู่กับว่าคุณรู้หลักการเขียนโปรแกรมภาษาและการใช้งานที่เฉพาะเจาะจงอย่างไร
คอลเล็กชันขยะ JavaScript คืออะไร
ตรวจสอบนี้
สิ่งสำคัญสำหรับผู้เขียนโปรแกรมเว็บคือต้องเข้าใจเกี่ยวกับการรวบรวมขยะ JavaScript เพื่อที่จะเขียนโค้ดที่ดีกว่า
ใน Javascript คุณไม่สนใจเรื่องการจัดสรรหน่วยความจำและการจัดสรรคืน ปัญหาทั้งหมดถูกเรียกร้องให้ล่าม Javascript การรั่วไหลยังคงเป็นไปได้ใน Javascript แต่เป็นข้อบกพร่องของล่าม หากคุณสนใจในหัวข้อนี้คุณสามารถอ่านเพิ่มเติมได้ที่ www.memorymanagement.org
บน windows คุณสามารถใช้Drip.exeเพื่อค้นหาหน่วยความจำรั่วหรือตรวจสอบว่ารูทีน mem ฟรีของคุณทำงาน
มันง่ายมากเพียงแค่ป้อน URL เว็บไซต์แล้วคุณจะเห็นปริมาณการใช้หน่วยความจำของตัวแสดงผล IE แบบรวม จากนั้นกดรีเฟรชหากหน่วยความจำเพิ่มขึ้นคุณจะพบหน่วยความจำรั่วบางแห่งบนหน้าเว็บ แต่นี่ก็มีประโยชน์มากเช่นกันเพื่อดูว่ารูทีนสำหรับการเพิ่มหน่วยความจำทำงานกับ IE ได้หรือไม่
ประเภทการอ้างอิงไม่ได้เก็บวัตถุไว้ในตัวแปรที่ได้รับมอบหมายโดยตรงดังนั้นตัวแปรวัตถุในตัวอย่างนี้จึงไม่ได้มีอินสแตนซ์ของวัตถุจริง แต่จะเก็บตัวชี้ (หรือการอ้างอิง) ไปยังตำแหน่งในหน่วยความจำที่มีวัตถุอยู่
var object = new Object();
หากคุณกำหนดตัวแปรหนึ่งให้กับตัวแปรอื่นแต่ละตัวแปรจะได้รับสำเนาของตัวชี้และทั้งคู่ยังคงอ้างอิงวัตถุเดียวกันในหน่วยความจำ
var object1 = new Object();
var object2 = object1;
JavaScript เป็นภาษาที่รวบรวมขยะดังนั้นคุณไม่จำเป็นต้องกังวลเกี่ยวกับการจัดสรรหน่วยความจำเมื่อคุณใช้ประเภทอ้างอิง แต่ดีที่สุดที่จะdereferenceวัตถุที่คุณไม่จำเป็นต้องเพื่อให้เก็บขยะสามารถเพิ่มหน่วยความจำที่ วิธีที่ดีที่สุดในการทำเช่นนี้คือการตั้งค่าตัวแปรวัตถุให้เป็นโมฆะ
var object1 = new Object();
// do something
object1 = null; // dereference
การอ้างอิงวัตถุมีความสำคัญอย่างยิ่งในแอปพลิเคชันขนาดใหญ่มากที่ใช้วัตถุนับล้าน
จากหลักการของ JavaScript เชิงวัตถุ - NICHOLAS C. ZAKAS