Какие ссылки проверяет сборщик мусора?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Ссылки, проверяемые сборщиком мусора в JavaScript
Сборщик мусора (Garbage Collector, GC) в JavaScript автоматически управляет памятью, освобождая объекты, которые больше недостижимы из корня. Современные движки (V8, SpiderMonkey, JavaScriptCore) используют алгоритм пометок (mark-and-sweep) с оптимизациями. GC проверяет достижимость объектов через цепочки ссылок, начиная от корневых объектов (roots).
Корневые объекты (Roots)
Сборщик начинает обход с "корней" — глобальных объектов и активных контекстов:
- Глобальный объект (
windowв браузере,globalв Node.js) - Активные контексты выполнения (локальные переменные и параметры функций в стеке вызовов)
- Встроенные объекты (встроенные классы, прототипы)
Типы ссылок, проверяемые GC
1. Прямые ссылки из корней
// Эти объекты достижимы напрямую из корней
global.user = { name: "Alice" }; // Ссылка из глобального объекта
const activeVar = { data: "temp" }; // В стеке вызова (доступна пока функция выполняется)
function process() {
const localObj = { value: 42 }; // Достижима пока выполняется process()
// После завершения функции localObj станет недостижима (если нет других ссылок)
}
2. Цепочки свойств объектов
const app = {
config: { theme: "dark" },
users: [{ id: 1 }, { id: 2 }]
};
// Если app достижим из корня, то все вложенные объекты также достижимы
// app → config → theme
// app → users → [0] → {id: 1}
3. Замыкания и лексическое окружение
function createCounter() {
let count = 0; // Переменная во внешнем лексическом окружении
return function() {
count++; // Замыкание сохраняет ссылку на count
return count;
};
}
const counter = createCounter();
// Пока counter достижим, переменная count также удерживается в памяти
// через цепочку: global → counter → [[Environment]] → count
4. Циклические ссылки
let objA = { name: "A" };
let objB = { name: "B" };
objA.ref = objB; // Ссылка из A на B
objB.ref = objA; // Обратная ссылка из B на A
// Если objA и objB НЕ достижимы из корней,
// они будут удалены несмотря на циклическую ссылку
// В устаревшем алгоритме reference-counting это вызвало бы утечку
5. Ссылки в DOM
// В браузерах ссылки между DOM и JavaScript проверяются особо
const element = document.getElementById("myDiv");
const handler = () => console.log("click");
element.addEventListener("click", handler);
// Пока element в DOM-дереве, handler не будет собран
// Если удалить элемент: element.remove(), handler может быть собран
6. Weak-ссылки (не проверяются как сильные)
// WeakMap, WeakSet, WeakRef не защищают объекты от сборки
const weakMap = new WeakMap();
let obj = { data: "secret" };
weakMap.set(obj, "metadata");
obj = null; // Объект { data: "secret" } может быть собран
// weakMap не предотвращает сборку, запись автоматически удалится
Критические аспекты проверки
- Достижимость, а не использование — GC удаляет объекты, до которых нельзя добраться из корней, а не просто неиспользуемые
- Неточность в определении корней — некоторые движки используют консервативный подход для стека
- Поколения объектов — современные GC делят объекты на молодые (часто меняющиеся) и старые (долгоживущие)
- Инкрементальная и параллельная сборка — чтобы не блокировать основной поток
Что НЕ проверяется как сильная ссылка
- WeakMap/WeakSet ключи — не препятствуют сборке ключей-объектов
- WeakRef — позволяет получить объект, но не предотвращает его сборку
- Symbol.weakRef — экспериментальное API для управления слабыми ссылками
Практический пример
// Пример утечки памяти из-за неожиданной достижимости
function createLeak() {
const hugeArray = new Array(1000000).fill("data");
// Неявная ссылка через обработчик события
document.addEventListener("scroll", () => {
// Обработчик ссылается на hugeArray через замыкание
console.log(hugeArray.length);
});
// Даже после завершения функции hugeArray остается достижима
// через обработчик события
}
// Для исправления нужно удалить обработчик
function fixedVersion() {
const hugeArray = new Array(1000000).fill("data");
const handler = () => console.log(hugeArray.length);
document.addEventListener("scroll", handler);
// Явное удаление позволяет собрать hugeArray
document.removeEventListener("scroll", handler);
}
Важно: сборщик мусора проверяет всю цепочку достижимости, поэтому "потерянные" ссылки на большие объекты могут создавать утечки памяти. Современные инструменты разработчика (Chrome DevTools Memory tab) помогают анализировать такие ситуации через снимки памяти (heap snapshots).