Circular Reference และ Memory Leak
Circular Reference: Object A Reference Object B, Object B Reference Object A กลับมาหากัน
ปัญหาในระบบ Reference Counting (เก่า/IE)
- Ref Count ไม่เป็น 0 → ไม่ถูก GC
- Memory Leak ถาวรจน Browser ปิด
ตัวอย่าง: DOM ↔ JS Object Circular Reference
<html> <body> <script>
window.onload = function() {
var obj = document.getElementById('DivElement');
// JS Object → DOM Element
document.getElementById('DivElement').expandoProperty = obj;
// DOM Element → JS Object (Circular!)
obj.bigData = new Array(1000).join(new Array(2000).join('x')); // 2MB+ Data
// Memory Leak: ทั้งคู่ไม่ถูก GC แม้ Window Unload
};
</script> </body> </html>
วิธีแก้: ตัด Circular Reference
window.onload = function() {
var obj = document.getElementById('DivElement');
document.getElementById('DivElement').expandoProperty = obj;
obj.bigData = new Array(1000).join(new Array(2000).join('x'));
obj = null; // ตัด Reference! ทั้งคู่กลายเป็น Unreachable → GC ได้
};
สถานการณ์ปัจจุบัน (Modern Browsers)
- Browser ใหม่ๆ (Chrome, Firefox, Edge, Safari) ใช้ Mark-Sweep GC → Circular Reference ไม่ใช่ปัญหา
- IE 6/7 มีปัญหา (Reference Counting สำหรับ DOM)
- แต่ยังควรตัด Reference เพื่อ Performance และกัน Leak ใน Edge Cases
Best Practices
- ตั้งค่า
nullให้ Variable/Property ที่ไม่ใช้แล้ว - ใช้
removeEventListenerลบ Listener - หลีกเลี่ยง Expando Property บน DOM Element
- ใช้ WeakMap/WeakSet สำหรับ Cache/Metadata