> Как устроен garbage collector (JavaScript)

Уровень: middle · Роль: frontend · Язык: JavaScript · Категория: Технические вопросы

Компании: ЭНИРАН

Стек: Node.js, JavaScript

> Пример ответа

Короткий ответ

Garbage collector (GC) в JavaScript - это автоматический механизм управления памятью, который освобождает память, занятую объектами, на которые больше нет ссылок. Основной алгоритм - mark-and-sweep: GC помечает достижимые объекты из корней (глобальный объект, текущий стек вызовов), затем удаляет непомеченные. В V8 (Node.js) используется поколенческая сборка: молодое поколение (new space) очищается часто, старое (old space) - реже.

Подробное объяснение

GC в JavaScript работает на основе достижимости (reachability). Память выделяется автоматически при создании объектов, а GC определяет, какие объекты больше не нужны. Основные этапы mark-and-sweep:

  1. Roots: сбор корневых ссылок (глобальные переменные, текущие функции, стеки).
  2. Mark: рекурсивный обход всех ссылок от корней, пометка каждого достижимого объекта.
  3. Sweep: освобождение памяти от непомеченных объектов.

В V8 (движок Node.js) GC поколенческий:

  • New space (молодое поколение): небольшая область для недавно созданных объектов. Сборка (Scavenge) происходит часто, используя алгоритм Cheney (копирование живых объектов в semi-space). Если объект переживает несколько сборок, он перемещается в old space.
  • Old space (старое поколение): для долгоживущих объектов. Используется mark-sweep и mark-compact (дефрагментация). Сборка реже, но дороже.

Инкрементальная сборка и параллельные потоки (в V8) уменьшают паузы. В Node.js GC может быть вызван явно через global.gc() (с флагом --expose-gc), но это не рекомендуется.

На практике

В Node.js GC влияет на производительность: частые сборки создают паузы (stop-the-world), особенно в old space. Для оптимизации:

  • Избегать утечек памяти (глобальные переменные, забытые таймеры, closures).
  • Использовать WeakMap/WeakSet для кэшей, чтобы GC мог удалить объекты при отсутствии других ссылок.
  • Мониторить память через process.memoryUsage() или Chrome DevTools (heap snapshot).
  • Для больших данных - буферы (Buffer) или Streams, чтобы не держать всё в памяти.

Пример утечки: setInterval с внешней ссылкой на объект не даёт GC удалить объект даже после вызова clearInterval, если ссылка остаётся.

Пример кода

JAVASCRIPT
// Утечка памяти через замыкание
function createLeak() {
const largeData = new Array(1000000).fill('x');
return function() {
console.log(largeData.length);
};
}
const leakyFunc = createLeak(); // largeData не освободится, пока leakyFunc существует
// Правильное использование WeakMap для кэша
const cache = new WeakMap();
function process(obj) {
if (!cache.has(obj)) {
cache.set(obj, { expensive: true });
}
return cache.get(obj);
}
// Когда obj удаляется извне, запись в WeakMap автоматически удаляется GC

Как отвечать на собеседовании

Начни с краткого определения GC как автоматического управления памятью. Затем объясни mark-and-sweep и поколенческий подход в V8. Упомяни, что GC в Node.js работает в основном потоке, вызывая паузы, но V8 использует инкрементальные и параллельные техники. Приведи пример утечки (глобальные переменные, closures) и способов их избежать (WeakMap, очистка ссылок). Если спросят про производительность, скажи, что важно минимизировать аллокации в hot path и использовать профилирование. Не углубляйся в детали реализации V8, если не спрашивают.

Что проверяет интервьюер

  • Понимание основ управления памятью в JS (стек vs куча, ссылочная модель).
  • Знание алгоритмов GC (mark-and-sweep, поколенческая сборка).
  • Практические навыки: как находить и предотвращать утечки памяти.
  • Осведомлённость о специфике Node.js (однопоточность, влияние GC на event loop).
  • Умение объяснить trade-off между частотой сборок и паузами.

Типичные ошибки

  • Путать GC в браузере и Node.js (в Node.js нет DOM, но GC аналогичен).
  • Думать, что GC работает по таймеру (на самом деле - по достижению порога памяти).
  • Считать, что присвоение null переменной немедленно освобождает память (GC срабатывает позже).
  • Игнорировать влияние closures и event listeners на утечки.
  • Предлагать delete для удаления свойств объектов (это не влияет на GC, только на структуру объекта).

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью