javascript 1.8.8 Сборка мусора

Управление памятью в JavaScript выполняется автоматически и незаметно. Мы создаём примитивы, объекты, функции… Всё это занимает память.

Но что происходит, когда что-то больше не нужно? Как JavaScript понимает, что пора очищать память?

Достижимость

Основной концепцией управления памятью в JavaScript является принцип достижимости.

Если упростить, то «достижимые» значения – это те, которые доступны или используются. Они гарантированно находятся в памяти.

  1. Существует базовое множество достижимых значений, которые не могут быть удалены.Например:
    • Локальные переменные и параметры текущей функции.
    • Переменные и параметры других функций в текущей цепочке вложенных вызовов.
    • Глобальные переменные.
    • (некоторые другие внутренние значения)
    Эти значения мы будем называть корнями.
  2. Любое другое значение считается достижимым, если оно доступно из корня по ссылке или по цепочке ссылок.Например, если в локальной переменной есть объект, и он имеет свойство, в котором хранится ссылка на другой объект, то этот объект считается достижимым. И те, на которые он ссылается, тоже достижимы. Далее вы познакомитесь с подробными примерами на эту тему.

В интерпретаторе JavaScript есть фоновый процесс, который называется сборщик мусора. Он следит за всеми объектами и удаляет те, которые стали недостижимы.

Простой пример

Вот самый простой пример:

// в user находится ссылка на объект
let user = {
  name: "John"
};

Здесь стрелка обозначает ссылку на объект. Глобальная переменная user ссылается на объект {name: "John"} (мы будем называть его просто «John»). В свойстве "name" объекта John хранится примитив, поэтому оно нарисовано внутри объекта.

Если перезаписать значение user, то ссылка потеряется:

user = null;

Теперь объект John становится недостижимым. К нему нет доступа, на него нет ссылок. Сборщик мусора удалит эти данные и освободит память.

Две ссылки

Представим, что мы скопировали ссылку из user в admin:

// в user находится ссылка на объект
let user = {
  name: "John"
};

let admin = user;

Теперь, если мы сделаем то же самое:

user = null;

…то объект John всё ещё достижим через глобальную переменную admin, поэтому он находится в памяти. Если бы мы также перезаписали admin, то John был бы удалён.

Взаимосвязанные объекты

Теперь более сложный пример. Семья:

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;

  return {
    father: man,
    mother: woman
  }
}

let family = marry({
  name: "John"
}, {
  name: "Ann"
});

Функция marry «женит» два объекта, давая им ссылки друг на друга, и возвращает новый объект, содержащий ссылки на два предыдущих.

В результате получаем такую структуру памяти:

На данный момент все объекты достижимы.

Теперь удалим две ссылки:

delete family.father;
delete family.mother.husband;

Недостаточно удалить только одну из этих ссылок, потому что все объекты останутся достижимыми.

Но если мы удалим обе, то увидим, что у объекта John больше нет входящих ссылок:

Исходящие ссылки не имеют значения. Только входящие ссылки могут сделать объект достижимым. Объект John теперь недостижим и будет удалён из памяти со всеми своими данными, которые также стали недоступны.

После сборки мусора:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *