Skip to main content

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

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

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

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

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

  1. Существует базовое множество достижимых значений, которые не могут быть удалены.

    Например:

    • Выполняемая в данный момент функция, её локальные переменные и параметры.
    • Другие функции в текущей цепочке вложенных вызовов, их локальные переменные и параметры.
    • Глобальные переменные.
    • (некоторые другие внутренние значения) Эти значения мы будем называть корнями.
  2. Любое другое значение считается достижимым, если оно доступно из корня по ссылке или по цепочке ссылок.

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

Внутренние алгоритмы

Основной алгоритм сборки мусора называется «алгоритм пометок» (от англ. «mark-and-sweep»).

Согласно этому алгоритму, сборщик мусора регулярно выполняет следующие шаги:

  • Сборщик мусора «помечает» (запоминает) все корневые объекты.
  • Затем он идёт по ним и «помечает» все ссылки из них.
  • Затем он идёт по отмеченным объектам и отмечает их ссылки. Все посещённые объекты запоминаются, чтобы в будущем не посещать один и тот же объект дважды.
  • …И так далее, пока не будут посещены все достижимые (из корней) ссылки.
  • Все непомеченные объекты удаляются.

Движки JavaScript применяют множество оптимизаций, чтобы она работала быстрее и не задерживала выполнение кода.

Вот некоторые из оптимизаций:

  • Сборка по поколениям (Generational collection) – объекты делятся на два набора: «новые» и «старые». В типичном коде многие объекты имеют короткую жизнь: они появляются, выполняют свою работу и быстро умирают, так что имеет смысл отслеживать новые объекты и, если это так, быстро очищать от них память. Те, которые выживают достаточно долго, становятся «старыми» и проверяются реже.
  • Инкрементальная сборка (Incremental collection) – если объектов много, и мы пытаемся обойти и пометить весь набор объектов сразу, это может занять некоторое время и привести к видимым задержкам в выполнении скрипта. Так что движок делит всё множество объектов на части, и далее очищает их одну за другой. Получается несколько небольших сборок мусора вместо одной всеобщей. Это требует дополнительного учёта для отслеживания изменений между частями, но зато получается много крошечных задержек вместо одной большой.
  • Сборка в свободное время (Idle-time collection) – чтобы уменьшить возможное влияние на производительность, сборщик мусора старается работать только во время простоя процессора.

Существуют и другие способы оптимизации и разновидности алгоритмов сборки мусора, потому что разные движки реализуют разные хитрости и методы.

Главное, что нужно знать:

  • Сборка мусора выполняется автоматически. Мы не можем ускорить или предотвратить её.
  • Объекты сохраняются в памяти, пока они достижимы.
  • Если на объект есть ссылка – вовсе не факт, что он является достижимым (из корня): набор взаимосвязанных объектов может стать недоступен в целом.

🚀 Источник: https://learn.javascript.ru/garbage-collection