Когда вы программируете на JavaScript, в большинстве случаев можно обойтись без знания того, как работает управление памятью. В конце концов, движок JavaScript делает все за вас.

Однако рано или поздно вы столкнетесь с некоторыми проблемами — например, с утечками памяти — и вы сможете избавиться от них только тогда, когда поймете, как именно работает распределение памяти.
В этой статье я расскажу вам об управлении памятью и о том, как работает сборщик мусора, а также объясню, как избежать наиболее распространенных видов утечек памяти.
Жизненный цикл памяти
В JavaScript, когда мы создаем функции, переменные и так далее, движок выделяет для них память и освобождает ее, как только память больше не нужна.
Выделение памяти — это процесс «резервирования» области памяти, а ее освобождение — это возврат памяти в систему, в результате чего ранее занятое пространство может быть повторно использовано.
Каждый раз, когда мы объявляем переменную или создаем функцию, необходимая память проходит следующие этапы:
Распределение памяти. JavaScript берет на себя эту задачу: он выделяет память, которая потребуется для созданного нами объекта.
Использование памяти. Это то, что мы явно пишем в коде: чтение и запись в память — это не что иное, как чтение и запись в переменную.
Освобождение памяти. Этот шаг также выполняется движком JavaScript: сразу после освобождения памяти вы можете использовать ее для других целей.
В контексте управления памятью «объекты» включают не только объекты JavaScript, но и функции с их областями действия.
Стек и куча
Теперь мы знаем, что движок JavaScript выделяет память под все, что мы определяем в коде, и освобождает ее, когда эта память больше не нужна. Это приводит к вопросу: где все хранится?
В JavaScript есть два варианта хранения данных: в стеке и в куче. Оба являются именами структур данных, которые используются движком для различных целей.
Стек: выделение статической памяти
Стек — это структура данных, используемая для хранения статических данных, т. е. данных, размер которых известен во время компиляции. В JavaScript к ним относятся примитивные значения (строка, число, логическое значение, неопределенное значение и нуль) и ссылки на функции и объекты.
Движок знает, что размер данных не изменится, и поэтому выделяет фиксированный объем памяти для каждого значения.
Процесс выделения памяти непосредственно перед выполнением называется статическим.
Поскольку для таких значений движок выделяет фиксированный объем памяти, логично предположить, что существует ограничение на размер примитивных значений. В зависимости от используемого браузера эти ограничения, а также максимально допустимый размер всего стека могут различаться.
Куча: динамическое выделение памяти
Куча (куча памяти) используется для хранения данных, таких как объекты и функции.
В отличие от стека, движок не знает, сколько памяти потребуется для тех или иных объектов, и поэтому выделяет память по мере необходимости.
Такое распределение памяти называется динамическим.
Использование памяти в JavaScript
Использование выделенной памяти в JavaScript обычно означает ее чтение и запись.
Это можно сделать, прочитав или записав значение переменной или свойства объекта или даже передав аргумент функции.
Освобождение памяти, которая больше не нужна
На этом этапе возникает большинство проблем с управлением памятью.
Самая сложная задача — выяснить, когда выделенная память больше не нужна программе. Для этого часто требуется, чтобы разработчик определил, где в программе определенный участок памяти больше не нужен, и освободил его.
Языки высокого уровня имеют встроенную подсистему, называемую сборщиком мусора. Роль этой подсистемы состоит в том, чтобы отслеживать операции выделения памяти и использовать ее, чтобы узнать, когда часть выделенной памяти больше не нужна. Если это так, сборщик мусора может автоматически освободить этот фрагмент.
К сожалению, этот процесс не является абсолютно точным, так как общая проблема выяснения, нужен ли тот или иной фрагмент памяти или нет, неразрешима (не решается алгоритмически).
Большинство сборщиков мусора работают, собирая память, к которой нет доступа, то есть к которой недоступны все переменные, указывающие на нее. Это, однако, слишком смелое предположение о возможности освобождения памяти, так как в любой момент времени некая область памяти может иметь указывающие на нее переменные в определенной области видимости, хотя эта область памяти никогда не будет обработана в программе.
Вывод
Итак, в статье кратко описаны ключевые понятия, лежащие в основе управления памятью в JavaScript. Мы говорили об управлении памятью, в частности особое внимание уделили процессу ее освобождения, так называемой сборке мусора. Именно на этом этапе жизненного цикла памяти возникают проблемы, которые выражаются в том, что память, занятая ненужными объектами, не может быть очищена. Как бы хорошо ни работали алгоритмы сборки мусора в современных реализациях JS-движков, программист должен помнить, что и на нем лежит определенная доля ответственности за рациональное использование памяти.