Эта статья является частью моей серии статей по основам javascript, в которой я пытаюсь объяснить основные концепции javascript. Если вы хотите узнать больше об этой серии, вы можете проверить мои более ранние статьи о подъеме в javascript и цикле событий и параллелизме JavaScript.

Управление памятью означает, как память выделяется, используется и очищается. Как мы видим, он имеет 3 шага.

  • Выделение памяти.Память выделяется операционной системой.
  • Использование памяти.Операции чтения/записи выполняются в выделенной памяти.
  • Освобождение памяти: память освобождается.

В таких языках, как C, у нас есть malloc() и free() для выделения и освобождения памяти. Таким образом, помимо решения бизнес-проблем, управления структурами данных, разработчики также должны заботиться о выделении и освобождении памяти.

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

Этот характер автоматического управления памятью javascript может создать у разработчика ложное впечатление, что ему не нужно заботиться об управлении памятью, что может повлиять на производительность веб-приложения.

Зачем нам нужно управление памятью:

  • Недостаток памяти: несмотря на то, что объем памяти, доступной в компьютере, значительно увеличился за последние несколько десятилетий, он все еще ограничен. Все переменные, исполняемые файлы, код операционной системы хранятся в памяти. Мы должны быть внимательны, чтобы использовать его и делиться им.
  • Если мы используем больше памяти, чем нам нужно оптимально, это может сделать наше приложение постоянно медленным.
  • У нас увеличено количество циклов сборки мусора, которые приостанавливают работу движка на короткое время. Это будет чаще блокировать приложение. В результате это приведет к плохому пользовательскому опыту.
  • Плохое управление памятью может замедлить рост приложения.

Давайте посмотрим, как работает автоматическое управление памятью в Javascript

  • Распределение памяти: когда объявляется любая переменная, выражение, функция, для нее выделяется некоторая память.

  • Использование памяти. При выполнении операций чтения/записи над переменными используется память.
  • Освобождение памяти: когда javascript определяет, что выделенная память «больше не требуется», он освобождает память. В движке запускается цикл сборки мусора, который пытается выяснить, какая память больше не используется, и освобождает ее. Давайте посмотрим, как этот сборщик мусора решает, какую память очистить.

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

Сборка мусора отвечает за очистку памяти. Он работает в течение короткого периода времени в течение некоторого времени. Машина останавливается на некоторое время, пока сборщик мусора выполняет свою работу. Поэтому частые циклы сборки мусора плохо влияют на производительность веб-приложения.

  • Сборка мусора с подсчетом ссылок. Используя этот алгоритм, сборщик мусора пытается найти ссылки на объекты или код. Если для него не найдена ссылка, сборщик мусора может очистить выделенную для него память.

проблема с этим типом сборки мусора - циклические ссылки. Предположим, два объекта ссылаются друг на друга, но их никто не использует. Даже когда память для них может быть освобождена, из-за этой циклической ссылки сборщик мусора не соберет эту память.

  • Маркировка и проверка:используя этот алгоритм, программа выполняет один цикл Маркировка, за которым следует цикл Проверка. В цикле маркировки он начинает выполнение из окна или глобального. Он продолжает отмечать все воспоминания, к которым он может получить доступ. В цикле Sweep он проходит через всю кучу. Освобождает недоступные воспоминания и сбрасывает отметку отмеченных воспоминаний.

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

Вот иллюстрация цикла маркировки и развертки от Минко Гечева

Итак, мы увидели, как выделяется, используется и освобождается память. Все выглядит хорошо. Давайте теперь перейдем к тому, в чем проблема в нем. Проблема возникает, когда память выделяется, но никогда не возвращается обратно в ОС. Это состояние называется Утечка памяти.

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

Возьмем сценарий.

  • Выделяется значительный объем памяти.
  • Используется память.
  • Никакого другого выделения памяти не происходит. Следовательно, GC больше не запускается.

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

Давайте посмотрим, как мы можем избежать утечки памяти:

Языки javascript высокого уровня, такие как Javascript, управляют собственным процессом управления памятью. Но, как мы видели выше, он использует некоторый алгоритм для освобождения памяти, и определить, требуется ли конкретный участок памяти или нет, по-прежнему неразрешимо. Как разработчики, мы должны иметь в виду, что мы не используем больше памяти, чем оптимально требуется, или что у нас нет ненужных воспоминаний.

Вот несколько примеров, которые могут привести к утечке памяти:

  1. Глобальные переменные. Javascript считает необъявленные переменные глобальными переменными. Поэтому, если мы используем какую-либо переменную, не объявляя ее, javascript добавляет ее в глобальную область видимости. Он никогда не выпускается, даже если он больше не требуется.

Чтобы избежать этого, мы также должны объявить нашу переменную в ее области видимости. Это позволяет сборщику мусора собирать эту память, когда он закончит свою работу.

Это правильный способ объявить переменную и использовать ее. Мы можем включить «строгий» режим, чтобы избежать таких сценариев.

2. Замыкания:замыкание — ключевая функция JavaScript. Когда есть функция, возвращающая другую функцию, внутренняя функция имеет доступ к переменным, объявленным во внешней функции.

Таким образом, возможно, что внутренняя функция удерживает часть неиспользуемой памяти, что может привести к утечке памяти.

В этом примере переменная res не требуется, но она сохраняет lo памяти. Это может вызвать утечку памяти.

Я запустил код в своем браузере. Давайте посмотрим на выделение памяти с помощью chrome dev tool.

Мы видим, что выделение памяти продолжает увеличиваться.

Об этом есть удивительная статья от Meteor.

3. Слушатели событий: иногда в модель DOM добавляются прослушиватели событий. Но разработчики не удаляют его, когда узел DOM исчез. Современные браузеры удаляют эти прослушиватели событий, когда узел DOM больше не присутствует. Но старые браузеры не удаляют этих прослушивателей и продолжают удерживать память. Мы должны помнить об удалении слушателей, когда его область уничтожена.

Это также применимо для таймеров. Когда установлен таймер, его также необходимо удалить.

4. Вне ссылок DOM:ссылки узлов DOM не должны храниться в других структурах данных. Это может привести к утечке памяти. Предположим, мы храним все элементы ‹li› в объекте. Затем мы удалили все ‹li›s, мы должны иметь в виду, что мы также удалили ссылки из объекта. В противном случае он не освободит выделенную для него память.

Это несколько примеров того, как мы можем избежать утечек памяти. Мы должны помнить о распределении, использовании и освобождении памяти во время разработки.

Поздравляем! Мы в конце статьи. Надеюсь, это поможет вам.

Спасибо за чтение!