Сборщик мусора

11-03-25 18:24:04


Image for the Сборщик мусора

Как работает управление памятью в JavaScript?

Когда мы создаем переменные, объекты или функции, они занимают память в оперативной памяти. В JavaScript процесс управления памятью состоит из трех этапов:

  1. Выделение памяти – создание переменных и объектов.
  2. Использование памяти – чтение, запись данных.
  3. Освобождение памяти – удаление данных, которые больше не нужны.

Пример создания и использования объектов:

let user = {
name: "Alex",
age: 30
};

// Используем объект
console.log(user.name); // "Alex"

// Теперь объект больше не нужен
user = null; // Помечен для удаления сборщиком мусора

После того как переменная user установлена в null, объект { name: "Alex", age: 30 } становится недоступным и сборщик мусора его удалит.

Основные алгоритмы сборки мусора

Счетчик ссылок (Reference Counting)

Этот метод отслеживает количество ссылок на объект. Когда счетчик ссылок становится равен нулю, объект удаляется.

let obj1 = { name: "John" };
let obj2 = obj1; // obj2 ссылается на obj1

obj1 = null; // obj2 всё ещё ссылается на объект, поэтому он не удаляется

obj2 = null; // Теперь объект больше не имеет ссылок и будет удалён

Принцип достижимости (Mark-and-Sweep)

​Этот алгоритм используется в современных движках JavaScript (V8, SpiderMonkey, Chakra). Он определяет "достижимые" объекты и удаляет те, к которым нельзя добраться.

  1. Помечает все активные объекты (например, глобальные переменные).
  2. Рекурсивно помечает все объекты, доступные из активных объектов.
  3. Удаляет все непомеченные объекты.
function createObject() {
let obj = { data: "some data" };
return obj;
}

let ref = createObject(); // объект сохранен в переменной ref
ref = null; // объект становится недоступным и будет удалён GC

Утечки памяти и их причины

Забытая ссылка

Если объект остается в памяти из-за ненужных ссылок, он не удаляется.

let user = {
name: "Alice"
};

let ref = user; // Вторая ссылка на объект
user = null; // Объект все еще доступен через ref

Решение: устанавливать ref = null, когда объект больше не нужен.

Замыкания

​Функции в JavaScript создают замыкания, которые могут привести к утечке памяти.

function createClosure() {
let bigArray = new Array(1000000).fill("data");

return function () {
console.log(bigArray.length);
};
}

let closure = createClosure();
// bigArray остаётся в памяти из-за замыкания

Решение: устанавливать bigArray = null внутри функции при ненадобности.

Утечки в DOM

​Если элемент удаляется из DOM, но на него остались ссылки в коде, он не будет очищен.

let button = document.createElement("button");
button.innerText = "Click me";
document.body.appendChild(button);

let reference = button;

document.body.removeChild(button); // Элемент удалён из DOM, но всё ещё доступен через reference

Решение: после удаления элемента из DOM устанавливать reference = null.

Оптимизация работы с памятью

1. Используйте let и const вместо var – так переменные живут только в своей области видимости.

2. Явно обнуляйте ненужные ссылки:

let obj = { data: "value" };
obj = null; // Объект освобождается

3. Избегайте хранения больших объектов в замыканиях.

4. Очищайте обработчики событий, если элемент больше не используется:

function onClick() {
console.log("Clicked");
}

let button = document.getElementById("myButton");
button.addEventListener("click", onClick);

// Удаляем обработчик при ненадобности
button.removeEventListener("click", onClick);

5. Используйте WeakMap и WeakSet для временных данных:

let weakMap = new WeakMap();
let obj = { name: "Alice" };

weakMap.set(obj, "data");
obj = null; // Объект будет автоматически удалён

Сборщик мусора автоматически очищает память, удаляя неиспользуемые объекты. Однако неправильное управление ссылками может приводить к утечкам памяти. Чтобы избежать проблем, важно следить за замыканиями, DOM-элементами и использовать слабые коллекции (WeakMap, WeakSet).