За последнее десятилетие в доступе к Интернету произошел большой сдвиг от «привилегированного класса» почти к любому, у кого есть устройство, способное подключаться к Интернету. Поскольку все больше и больше людей получают доступ к Интернету, разработчики сталкиваются с серьезной проблемой управления нагрузкой на приложение. Утечки памяти были самым распространенным врагом для технологической индустрии, с которой приходится бороться каждый день с растущей пользовательской базой и, кроме того, растущей кодовой базой с множеством функций, добавляемых в каждом втором выпуске программного обеспечения. Утечки памяти могут привести к таким проблемам, как замедление работы приложений, сбои, высокая задержка и т. д.

Для низкоуровневых языков, таких как C, разработчикам приходится вручную управлять памятью с помощью malloc и calloc. Напротив, JavaScript автоматически выделяет память при создании объектов и освобождает ее, когда они больше не используются. Этот процесс известен как Сборка мусора. Но означает ли это, что разработчики JavaScript живут без знаний об управлении памятью? Точно нет! Всякий раз, когда Node.js плохо освещается в прессе, это (как правило) связано с проблемами производительности. Пользователь должен просто знать некоторые вещи о том, как работает Node.js.

Независимо от языка программирования цикл сборки мусора очень похож.

Сборка мусора с подсчетом ссылок

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

Ограничение: Циклические ссылки

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

Обратите внимание, что узлы с циклическими ссылками не удаляются из памяти.

Алгоритм пометки и развертки

Этот алгоритм сводит определение «объект больше не нужен» к «объект недоступен». Этот алгоритм предполагает знание наборов объектов, называемых корнями. В Javascript корень является глобальным объектом. Таким образом, сборщик мусора начнет с корней, найдет все объекты, на которые есть ссылки из этих корней, и объекты, на которые есть ссылки из них, и так далее. Таким образом, он находит достижимые и недостижимые объекты.

Затем GC освобождает недоступные объекты из памяти. Это решает проблему циклических ссылок. Если два объекта с циклическими ссылками существуют в памяти и недоступны прямо или косвенно через корни, то они освобождаются из памяти. Этот алгоритм подробно описан в разделе управления памятью Node.js.

Управление памятью в Nodejs

Google V8 — это движок JavaScript, изначально созданный для Google Chrome, но его также можно использовать отдельно. Это делает его идеальным для Node.js. V8 компилирует JavaScript в нативный код и выполняет его.

Схема памяти V8

Работающая программа представлена ​​в виде области памяти, называемой Resident Set. Это делит память на определенные наборы:

Код: фактически выполняемый код.

Стек: содержит статические данные, такие как кадры функций, примитивные значения (например, логические или целые числа), указатели на объекты в куче и т. д.

Куча: V8 хранит объекты или динамические данные в куче. Это самый большой блок области памяти, и именно здесь происходит сборка мусора (GC).

Совет. Текущее использование памяти в Node.js можно проверить, вызвав process.memoryUsage().

Куча

Рассмотрим следующий код:

Здесь и a, и b будут помещены в стек.

куча

Теперь рассмотрим следующий код:

После этого память Heap будет выглядеть примерно так:

Теперь давайте еще два объекта:

наша память обновляется до:

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

Учтите, мы больше не используем объект Pizza. Допустим, мы установили для Pizza значение undefined. (Обратите внимание, чтобы изменить значение пиццы, вам нужно использовать ключевое слово «let», чтобы сделать начальное определение пиццы, а не const)

Теперь память будет выглядеть примерно так:

Теперь при запуске GC исходный объект Pizza не может быть доступен из корневого объекта, поэтому при следующем запуске сборщика мусора он будет освобожден:

Что вызывает утечку памяти в JS

Итак, самая большая дилемма заключается в том, что если в JS уже есть автоматизированный сборщик мусора, то зачем разработчику узнавать об утечках памяти? У Javascript все еще есть утечки памяти? Ответ положительный.

Несмотря на то, что автоматическое управление памятью, такое как сборка мусора в V8, позволяет избежать большинства утечек памяти, в куче все еще могут быть нежелательные ссылки на память, которые могут возникать по разным причинам.

Глобальные переменные. Поскольку глобальные переменные в JS существуют в глобальном контексте выполнения (GEC), на эти переменные всегда ссылается корневой узел (окно или глобальный this) они никогда не удаляются сборщиком мусора на протяжении всего жизненного цикла приложения и занимают память. Наличие большого графа объектов, на которые ссылается корень, может вызвать утечку памяти.

Несколько ссылок. Может быть случай, когда на один и тот же объект ссылаются несколько объектов, а одна из ссылок остается висящей.

Замыкания. Замыкание в Javascript — отличный инструмент, помогающий запомнить контекст. Когда замыкание содержит ссылку на большой объект в куче, объект остается в памяти до тех пор, пока используется это конкретное замыкание. Если замыкания используются неправильно, это может привести к утечке памяти.

Таймеры и события. Использование setTimeout, setInterval, наблюдателей и прослушивателей событий может привести к утечке памяти, если в их обратном вызове сохраняются ссылки на большие объекты без надлежащей обработки.

первоначально опубликовано на amodshinde.com