Память и сборщик мусора, утечки

↑ 2.1 JavaScript: продвинутый · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: middle

Зачем это на собесе

Утечки памяти в SPA — частая проблема; ждут перечня причин и способов найти.

Объяснение

Память управляется автоматически. Алгоритм GC — mark-and-sweep: от корней (глобальный объект, стек, активные замыкания) помечаются достижимые объекты; остальные удаляются. Циклические ссылки не мешают освобождению. Современный V8 — поколенческий (young/old), инкрементальный и параллельный GC.

Утечка — объекты, ставшие ненужными, но остающиеся достижимыми.

ПричинаПримерРешение
Глобальные переменныеслучайное присваивание без объявленияstrict mode, линтер
Забытые таймерыsetInterval без clearIntervalочистка в unmounted
Слушатели событийaddEventListener без снятия; слушатели на window/documentremoveEventListener, AbortController
Замыканияудерживают большие объектыобнулять ссылки, не захватывать лишнее
Отсоединённые DOM-узлыссылка в JS на удалённый элементnull, WeakRef/WeakMap
Неограниченные кэши, сторнакопление без вытесненияLRU, лимиты, TTL
Подписки (RxJS, WebSocket, EventBus)не отписалисьотписка в onUnmounted
Сторонние библиотекиинстансы карт/графиков не уничтоженыdestroy()
// Vue
onMounted(() => { timer = setInterval(tick, 1000); window.addEventListener("resize", onResize); });
onUnmounted(() => { clearInterval(timer); window.removeEventListener("resize", onResize); });
 
const ctrl = new AbortController();
window.addEventListener("scroll", onScroll, { signal: ctrl.signal });   // ctrl.abort() снимает

Диагностика (Chrome DevTools → Memory): снимки кучи (Heap snapshot) до/после действия и сравнение (Comparison), «Allocation instrumentation on timeline», вкладка Performance → флажок Memory, поиск Detached DOM nodes. Признак утечки: пилообразный график, не возвращающийся к базовой линии.

Нюансы и подводные камни

  • WeakRef и FinalizationRegistry не гарантируют время очистки; используйте редко.
  • Большие ArrayBuffer/Blob освобождаются не сразу: URL.revokeObjectURL.
  • SPA живёт часами: небольшая утечка накапливается.
  • Утечки часто связаны с компонентами, которые не размонтируются (кэш KeepAlive).

Практика

  1. Воспроизведите утечку через таймер и найдите её в Heap snapshot.
  2. Сравните два снимка после открытия/закрытия модального окна 20 раз.
  3. Добавьте очистку в onUnmounted для всех подписок.

Вопросы с ответами

Связанные темы