Управление памятью JavaScript выполняется автоматически и незаметно для нас. Мы создаем примитивы, объекты, функции… Все это требует памяти.
Что происходит, когда что-то большее не нужно? Как механизм JavaScript это обнаруживает и очищает?
В этой статье узнаем, что такое Garbage collection (GC), для чего он нужен вообще и какие проблемы решает.
Для понимания: первый язык, который поддерживал сбор мусора - это был язык APL в 1964 году. Вы только представьте, что даже 60 лет назад люди уже думали о том, что нужно попытаться уволить время разработчиков для более полезных задач!
GC (Garbage Collection - сбор мусора) - высокоуровневая абстракция, которая лишает разработчиков необходимости заботиться об освобождении управляемой памяти.
Сейчас JS, как и многие другие языки программирования, обладают способностью активно модифицировать типы данных, поэтому двигателям необходимо находить решения для работы с неконтролируемым использованием памяти.
Основной концепцией управления памятью в JavaScript является доступность. Собиратель мусора следит за всеми объектами и удаляет ставшие недоступными.
Проще говоря, «доступные» значения — это доступные или которые можно использовать. Они гарантированно хранятся в памяти.
Какие это значения:
- Функция, выполняемая в данный момент, ее локальные переменные и параметры.
- Другие функции в текущей цепочке вложенных вызовов, их локальные переменные и параметры.
- Глобальные переменные.
Рекомендуем курс по теме
Как происходит процесс уборки мусора?
Это процесс неуправляемый и мы не можем его предотвратить или ускорить.
GC пытается запуститься только тогда, когда процессор неактивен, чтобы снизить возможное влияние на выполнение и не тормозить процессы.
Основной алгоритм сбора мусора называется «обознач и убери».
Регулярно выполняются следующие шаги:
- Собиратель мусора берет <root>'s и «обозначает» (т.е. запоминает) их.
- Затем он проходит по ним и «обозначает» все ссылки, которые есть внутри.
- Затем он проходит по уже обозначенным объектам и обозначает их ссылку. Все посещаемые объекты запоминаются, чтобы не посещать один и тот же объект дважды в будущем.
- …И так далее, пока не будет посещена каждая доступная (от корней) ссылка.
- Все объекты, кроме отмеченных, удаляются.
Пример для объяснения
Структура объекта выглядит так:С правой стороны видны объекты, к которым ничего не ведет. Еще они могут называться "недоступным островом".
Первый шаг – обозначает <root>’s:
Затем мы следуем за их ссылками и отмечаем объекты, на которые они ссылаются:
Продолжаем следить за дальнейшими ссылками, пока это возможно:
Теперь объекты, по которым не удалось пройтись в процессе, считаются недоступными и будут удалены:
В сборке мусора имеется важный термин: "Гипотеза поколений". Согласно этой гипотезе, объекты программы обычно имеют разные "возрастные" характеристики: большинство объектов создаются в начале выполнения программы и быстро становятся ненужными, в то время как некоторые объекты существуют дольше. Итак, основная мысль гипотезы поколений состоит в том, что объекты можно поделить на несколько "поколений", при этом каждое поколение имеет свои свойства относительно продолжительности жизни объектов.
Поколение:
- молодое (young)
- среднее (middle)
- старое (old)
Новые объекты обычно создаются в молодом поколении. Средним поколением они становятся после определенного количества занятой памяти или определенного количества итераций. Если объекты выживают, то они переходят в следующее поколение. Грубо говоря, сборка мусора происходит между каждым таким переходом. Старые поколения, в свою очередь, редко подвергаются проверкам сборником мусора, потому что объекты внутри них принято считать более устойчивыми.
Как мы можем оптимизировать работу с памятью, помогая тем самым GC?
За столь долгое существование проблем с памятью разработчики выделили несколько основных стратегий оптимизации кода:
1. Пытаемся избегать утечки памяти:
- Используем замыкания и другие механизмы управления областями видимости и памятью
2. Избегаем глубокой вложенности:
- Это может привести к еще большему объему памяти, который нужно будет собирать.
3. Эффективное использование памяти:
- Если это возможно, лучше избегать больших объектов и массивов, разделяя их на модули и отдельные массивы.
4. Оптимизация циклов предупреждает сверхзамену рекурсии
- Чрезмерная рекурсия может привести к созданию многих ненужных объектов в памяти.
5. Используйте встроенные методы оптимизации работы с памятью:
- JavaScript и другие языки программирования предоставляют встроенные методы оптимизации работы с памятью, такие как методы управления памятью типа "WeakMap" или "WeakSet".
6. Минимизировать создание ненужных объектов:
- Вместо создания новых объектов каждый раз, когда это возможно, используйте существующие.
Вывод
Механизм сбора мусора является важной составляющей автоматического управления памятью, которое делает разработку программ более безопасной и удобной для разработчиков.
Для улучшения производительности кода и оптимизации использования ресурсов важно исследовать глубокие процессы в языках программирования и изучать лучшие практики программирования. Узнавать разные алгоритмы, шаблоны проектирования и оптимизационные техники поможет писать чистый, эффективный и оптимизированный код.
Эти рекомендации позволят разработчикам лучше понимать принципы работы языка и использовать его возможности максимально эффективно.
Пишите, проверяйте, учитесь и обязательно наслаждайтесь этим процессом.