Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

Forgotten Timers/Callbacks ก่อให้เกิด Memory Leak ใน JavaScript

Timers และ Memory Leak

setTimeout() และ setInterval() เป็นสาเหตุ Memory Leak บ่อยที่สุด Object ที่ผูกกับ Timer ไม่ถูก GC จน Timer Expire/Clear

ตัวอย่างปัญหา

<script>
  for (var i = 0; i < 100000; i++) {
    var tiedObject = {
      callAgain: function() {
        var self = this;
        var timerId = setTimeout(function() {
          self.callAgain(); // Closure captures tiedObject
        }, 100000);
      }
    };
    tiedObject.callAgain();
    tiedObject = null; // Variable null แต่ Timer ยัง Reference อยู่!
  }
</script>

ผล: 100,000 Timer + Object ค้างใน Memory

วิธีป้องกัน

1. Clear Timer เมื่อไม่ใช้

const timerId = setInterval(() => { /* ... */ }, 1000);
// ตอน Cleanup:
clearInterval(timerId);

2. ใช้ WeakRef/FinalizationRegistry (ES2021)

const registry = new FinalizationRegistry(heldValue => {
  console.log('Cleanup:', heldValue);
});

function createTimer(obj) {
  const timerId = setInterval(() => obj.doWork(), 1000);
  registry.register(obj, timerId, obj); // Register Cleanup
  return timerId;
}

3. AbortController Pattern (Modern)

const controller = new AbortController();
const signal = controller.signal;

setTimeout(() => {
  if (!signal.aborted) doWork();
}, 1000);

// Cancel:
controller.abort();

4. Library จัดการให้ (jQuery, RxJS, Lodash)

Modern Libraries จัดการ Cleanup เอง แต่ Custom Code ต้องระวัง

Best Practices

  • เก็บ Timer ID ไว้เสมอ: const id = setInterval(...)
  • Clear ใน Cleanup/Unmount (React: useEffect Return, Vue: onUnmounted)
  • หลีกเลี่ยง Anonymous Function ใน Timer (ยาก Clear)
  • ใช้ setTimeout แทน setInterval สำหรับ Recurring (หลีกเลี่ยง Drift)