</>
⌕
Senior #memory#gc#memory-leak#performance

Garbage collection hoạt động thế nào? Các nguyên nhân memory leak phổ biến

⚡ Trả lời nhanh

JS dùng mark-and-sweep: object không còn reachable từ root (global, call stack) thì bị thu hồi; reference counting không xử lý được vòng tham chiếu. Leak xảy ra khi còn tham chiếu không cần: global, listener/timer chưa dọn, closure giữ object lớn, cache không giới hạn, DOM detached.

Cơ chế

Engine (V8) đánh dấu mọi object reachable từ root rồi giải phóng phần còn lại (mark-and-sweep). Vòng tham chiếu a.b = b; b.a = a không phải vấn đề nếu cả hai không còn reachable. V8 dùng generational GC: object mới ở young generation (thu hồi nhanh, thường xuyên), sống sót lâu được chuyển sang old generation. GC chạy xen kẽ/ đồng thời để giảm pause nhưng vẫn không hoàn toàn xác định thời điểm.

Nguyên nhân leak thường gặp

Nguyên nhânCách xử lý
Biến global vô tình (thiếu khai báo)strict mode, module
addEventListener, setInterval không gỡremoveEventListener, clearInterval, AbortController
Closure giữ object lớnkhông capture thứ không dùng
Cache/Map tăng vô hạngiới hạn kích thước (LRU), WeakMap
DOM node đã xóa nhưng vẫn được tham chiếubỏ tham chiếu khi remove
Subscription (RxJS, WebSocket) không unsubscribecleanup trong useEffect return
function mount(el) {
  const ctrl = new AbortController();
  window.addEventListener("resize", onResize, { signal: ctrl.signal });
  return () => ctrl.abort(); // gỡ listener một lần
}
🃏 Ôn bằng flashcard