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

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

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

Начните с полного автоматизированного тестирования с использованием селена. Узнайте, что такое Selenium, его архитектура, преимущества и многое другое для автоматического кроссбраузерного тестирования: https://www.lambdatest.com/selenium

Что такое утечки памяти в JavaScript?

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

Javascript достаточно умен, чтобы определить, когда переменная вам больше не понадобится, и очистить ее для экономии памяти. Утечка памяти Javascript происходит, когда вам больше не нужен объект, но среда выполнения JS все еще думает, что он вам нужен.

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

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

Что такое цикл памяти?

«Память» состоит из серии триггеров, которые представляют собой схему с двумя состояниями (0 и 1), состоящую из 4–6 транзисторов. Как только триггер сохранит бит, он будет продолжать сохранять его до тех пор, пока не будет перезаписан противоположным битом. Таким образом, память — это не что иное, как массив перепрограммируемых битов. Каждый фрагмент данных, используемый в программе, хранится в памяти.

Цикл памяти — это полная последовательность событий, при которой единица памяти переходит из состояния простоя/свободы через фазу использования (чтение или запись) и обратно в состояние простоя. Цикл памяти можно условно разделить на 3 основных этапа:

Узнайте, почему Python — лучший выбор для автоматизированного тестирования. Это подробное руководство представляет собой пошаговое руководство по автоматическому тестированию Python, которое поможет вам оптимизировать процесс тестирования: https://www.lambdatest.com/blog/python-automation-testing/

1. Распределение памяти: память выделяется ОС программе во время выполнения по мере необходимости. В языках низкого уровня, таких как C и C++, этот шаг выполняется программистом, но в языках высокого уровня, таких как javascript, это делается самостоятельно с помощью автоматической системы управления памятью. Некоторые примеры распределения памяти в JavaScript –

var n = 5; // allocates memory for a number
       var s = 'Hello World'; // allocates memory for a string
       var obj = { // allocates memory for an object
           a: 100,
           b: "some string",
           c: null,
       };
       var arr = [100, "some string", null]; // allocates memory for the array
       function foo(x, y) { // allocates memory for a function
           return x * y;
       }

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

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

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

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

Вот краткий обзор сертификации Selenium JavaScript 101 от LambdaTest:

Вот руководство по автоматическому тестированию мобильных приложений с помощью appium, мощной платформы, которая поможет вам оптимизировать процесс тестирования: https://www.lambdatest.com/blog/how-to-automate-android- приложения-использование-appium/

Системы управления памятью — Ручной vs Автоматический

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

  • Языки низкого уровня, такие как Pascal, C и C++, имеют систему ручного управления памятью, в которой программист должен вручную/явно выделять память, когда это необходимо, а затем освобождать память после того, как она была использована программой. Например, C использует malloc() и calloc() для резервирования памяти, realloc() для перемещения зарезервированного блока памяти в другое место и free() для освобождения памяти обратно в систему.
  • Языки программирования высокого уровня, такие как Javascript и VB, имеют автоматизированную систему, которая выделяет память каждый раз, когда вы создаете объект, например объект, массив, строку или элемент DOM, и автоматически освобождает ее, когда они больше не используются. процесс, называемый сбором мусора. Утечки памяти происходят, когда ваша программа все еще потребляет память, которая в идеале должна быть освобождена после завершения данной задачи. По какой-то причине сборщик мусора не выполняет свою функцию, и программа отказывается освобождать память, которая продолжает потребляться без какой-либо необходимости в этом.

Узнайте, почему Python — лучший выбор для автоматизированного тестирования. Это подробное руководство представляет собой пошаговое руководство по автоматическому тестированию на Python, которое поможет вам оптимизировать процесс тестирования: https://www.lambdatest.com/blog/python-automation-testing/

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

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

Хотя метод сбора мусора очень эффективен, утечки памяти Javascript все же возможны. Основной причиной таких утечек очень часто является «нежелательная ссылка».

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

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

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

В этом руководстве по Selenium с Java вы изучите Java для автоматизированного тестирования и все, что вам нужно знать, чтобы начать свой путь в автоматизации тестирования Selenium с помощью Java: https://www.lambdatest.com/blog/selenium- с-java/

Два самых популярных алгоритма:

  1. Количество ссылок
  2. Отметить и очистить
  • Алгоритм подсчета ссылок

Этот алгоритм основан на понятии «ссылка». Он основан на подсчете количества ссылок на объект от других объектов. Каждый раз, когда создается объект или назначается ссылка на объект, его счетчик ссылок увеличивается. В JavaScript каждый объект имеет неявную ссылку на свой прототип и явную ссылку на значения его свойств.

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

<script>
       var o = { // 2 objects are created. One is referenced by the other as one of its properties.
           a: { // The other is referenced by virtue of being assigned to the 'o' variable.
               b: 2; // Obviously, none can be garbage-collected
           }
       };
 
       var o2 = o; // the 'o2' variable is the second thing that has a reference to the object
       o = 1; // now, the object that was originally in 'o' has a unique reference embodied by the 'o2' variable
       var oa = o2.a; // reference to 'a' property of the object.This object now has 2 references: one as a property,
       // the other as the 'oa' variable
       o2 = 'yo'; // The object that was originally in 'o' has now zero references to it. It can be garbage-collected.
       // However its 'a' property is still referenced by the 'oa' variable, so it cannot be freed
       oa = null; // The 'a' property of the object originally in o has zero references to it. It can be garbage collected.
       };
</script>

Недостаток алгоритма подсчета ссылок

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

<script>
       function foo() {
           var obj1 = {};
           var obj2 = {};
           obj1.x = obj2; // obj1 references obj2
           obj2.x = obj1; // obj2 references obj1
 
           return true;
       }
       foo();
</script>
  • Алгоритм маркировки и очистки

В отличие от алгоритма подсчета ссылок, Mark-and-Sweep сводит определение «объект больше не нужен» к «объект недоступен», а не к «нет ссылки».
В javascript глобальный объект называется ' корень'.

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

Алгоритм Mark-and-Sweep работает в два этапа:

1. Отметить этап

Каждый раз, когда объект создается, его бит метки устанавливается в 0 (ложь). На этапе маркировки бит метки каждого «доступного» объекта изменяется и устанавливается в 1 (истина).

2. Фаза развертки

Все те объекты, у которых бит метки все еще установлен в 0 (ложь) после фазы метки, являются недостижимыми объектами и, следовательно, они собираются мусором и освобождаются из памяти алгоритмом.

Узнайте о 9 лучших фреймворках Javascript для автоматизации тестирования и выберите наиболее подходящие фреймворки в зависимости от требований вашего проекта: https://www.lambdatest.com/blog/top-javascript-automation-testing-framework/

У всех объектов изначально отмеченные биты установлены в 0 (ложь)

Все доступные объекты имеют отмеченные биты изменены на 1 (истина)

Недоступные объекты удаляются из памяти.

Преимущества алгоритма маркировки и очистки

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

Недостатки алгоритма маркировки и очистки

Основным недостатком этого подхода является то, что выполнение программы приостанавливается на время работы алгоритма сборщика мусора.

Проверьте свой веб-сайт или веб-приложение онлайн на совместимость с браузером iOS. Выполните бесшовное кроссбраузерное тестирование на новейшем симуляторе тестера iPhone. Попробуйте бесплатно!
https://www.lambdatest.com/test-on-iphone-simulator

Причины утечек памяти Javascript

Самый важный ключ к предотвращению утечек памяти Javascript заключается в понимании того, как создаются нежелательные ссылки. В зависимости от характера этих нежелательных ссылок мы можем разделить источники памяти на 7 типов:

1. Необъявленные/случайные глобальные переменные

В JavaScript есть два типа областей действия — локальная и глобальная. Область определяет видимость переменных, функций и объектов во время выполнения.

  • Переменные с локальной областью доступны и видимы только в пределах своей локальной области (где они определены). Говорят, что локальные переменные имеют «область действия»: доступ к ним возможен только изнутри функции.
<script>
       // Outside myFunction() variable ‘a’ cannot be accessed
       function myFunction() {
           var a = "This is a local scope variable";
           // variable ‘a’ is accessible only inside myFunction()
       }
</script>
  • С другой стороны, к переменным с глобальной областью доступа могут обращаться все скрипты и функции в документе JavaScript. Когда вы начинаете писать JavaScript в документе, вы уже находитесь в глобальной области видимости. В отличие от локальной области, в документе JavaScript существует только одна глобальная область. Все глобальные переменные принадлежат объекту окна.

Если вы присвоите значение переменной, которая ранее не была объявлена, она автоматически станет «глобальной переменной».

<script>
       // variable ‘a’ can be accessed globally
       var a = "This is a global variable";
 
       function myFunction() {
           // the variable a is accessible here inside the myFunction() as well
       }
</script>

WebDriver — это интерфейс удаленного программирования, который можно использовать для управления браузером локально или на удаленном компьютере. Узнайте больше в этом полном руководстве по Selenium WebDriver: https://www.lambdatest.com/learning-hub/webdriver.

Случай случайной глобальной переменной:

Если вы присвоите значение переменной без предварительного объявления, это создаст «автоматическую» или «случайную глобальную переменную». В этом примере будет объявлена ​​глобальная переменная a, даже если ей присвоено значение внутри функции.

<script>
       // variable ‘a’ has global scope
       function myFunction() {
           a = "this is an accidental global variable";
           // variable ‘a’ is global as it has been assigned a value without prior declaration
       }
</script>

РЕШЕНИЕ. Глобальные переменные по определению не удаляются сборщиками мусора. Вот почему для Javascript-программиста всегда важно осторожно использовать глобальные переменные и никогда не забывать обнулять их или переназначать после их использования. В приведенном выше примере установите для глобальной переменной a значение null после вызова функции. Другой способ — использовать «строгий» режим для анализа вашего JS-кода. Это предотвратит создание необъявленных случайных глобальных переменных. Другой способ — использовать «let» вместо «var» для объявления переменных. Let имеет область действия блока. Его область действия ограничена блоком, оператором или выражением. Это отличается от ключевого слова var, которое определяет переменную глобально.

2. Замыкания

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

Утечка памяти происходит при замыкании, если переменная, объявленная во внешней функции, автоматически становится доступной для вложенной внутренней функции и продолжает находиться в памяти, даже если она не используется/ссылается на нее во вложенной функции.

Полное руководство по повторному тестированию, которое проливает свет на его особенности, важность, плюсы и минусы, а также на то, как его проводить: https://www.lambdatest.com/learning-hub/retesting

<script>
   var newElem;
 
   function outer() {
       var someText = new Array(1000000);
       var elem = newElem;
 
       function inner() {
           if (elem) return someText;
       }
 
       return function () {};
   }
 
   setInterval(function () {
       newElem = outer();
   }, 5);
</script>

В приведенном выше примере функция Internal никогда не вызывается, но сохраняет ссылку на elem. Но поскольку все внутренние функции в замыкании используют один и тот же контекст, внутренняя (строка 7) использует тот же контекст, что и функция (строка 12), возвращаемая внешней функцией.

Теперь каждые 5 мс мы вызываем функцию external и присваиваем ее новое значение (после каждого вызова) newElem, которая является глобальной переменной. Пока ссылка указывает на эту функцию(){}, общая область видимости/контекст сохраняется, а someText сохраняется, поскольку он является частью внутренней функции, даже если внутренняя функция никогда не вызывается.

Каждый раз, когда мы вызываем external, мы сохраняем предыдущую функцию(){} в элементе новой функции. Поэтому снова необходимо сохранить предыдущую общую область/контекст. Таким образом, при n-м вызове внешней функции someText (n-1)-го вызова внешней функции не может быть подвергнут сборке мусора. Этот процесс продолжается до тех пор, пока в вашей системе не закончится память.

РЕШЕНИЕ: Проблема в этом случае возникает из-за того, что ссылка на функцию(){} сохраняется. Утечки памяти в JavaScript не будет, если на самом деле будет вызвана внешняя функция (вызовите внешнюю функцию в строке 15, например, newElem = external()();). Небольшая изолированная утечка памяти JavaScript, возникшая в результате замыканий, возможно, не требует никакого внимания. Однако периодические утечки, повторяющиеся и увеличивающиеся с каждой итерацией, могут серьезно снизить производительность вашего кода.

3. Ссылка на отдельный DOM/вне DOM

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

DOM — это двусвязное дерево, ссылка на любой узел дерева предотвратит сбор мусора во всем дереве. Давайте возьмем пример создания элемента DOM в javascript, а затем в какой-то момент удаления этого элемента (или его родительского элемента), но забываем удалить переменную, содержащую его. Это приводит к созданию отдельного DOM, который содержит ссылку не только на элемент DOM, но и на все дерево.

<script>
       var demo = document.createElement("p");
       demo.id = "myText";
       document.body.appendChild(demo);
       var lib = {
           text: document.getElementById('myText')
       };
 
       function createFunction() {
           lib.text.innerHTML = "hello World";
       }
       createFunction();
 
       function deleteFunction() {
           document.body.removeChild(document.getElementById('myText'));
       }
       deleteFunction();
</script>

Онлайн Selenium Grid для запуска сценариев автоматизации тестирования вашего браузера в облачной инфраструктуре, содержащей более 3000 настольных и мобильных браузерных сред. Выполняйте тестирование Selenium в сетке облачного автоматизации тестирования, которая масштабируется вместе с вашими тестами: https://www.lambdatest.com/selenium-grid-online

Даже после удаления #myText из DOM у нас все еще есть ссылка на #myText в глобальном объекте библиотеки. Вот почему он не может быть освобожден сборщиком мусора и будет продолжать потреблять память. Это еще один случай утечки памяти, которого следует избегать путем настройки кода.

РЕШЕНИЕ: В качестве наилучшей практики использования JavaScript обычно используется размещение демо-версии var внутри прослушивателя, что делает ее локальной переменной. При удалении демо путь к объекту обрезается. Сборщик мусора может освободить эту память.

4. Таймеры

В Javascript есть два события синхронизации, а именно — setTimeout и setInterval. «setTimeout()» выполняет функцию после ожидания указанного количества миллисекунд, в то время как «setInterval()» выполняет некоторые действия, но постоянно повторяет выполнение функции. Методы setTimeout() и setInterval() являются методами объекта HTML DOM Window. Таймеры Javascript являются наиболее частой причиной утечек памяти, поскольку их использование довольно распространено.

Рассмотрим следующий код JavaScript, включающий таймеры, который создает утечку памяти.

<script>
       for (var i = 0; i < 100000; i++) {
           var buggyObject = {
               callAgain: function() {
                   var ref = this;
                   var val = setTimeout(function() {
                       ref.callAgain();
                   }, 1000000);
               }
           }
           buggyObject.callAgain();
           buggyObject = null;
       }
</script>

Выполняйте автоматические тесты Jest параллельно в нескольких комбинациях браузеров и ОС с помощью LambdaTest: https://www.lambdatest.com/jest

Обратный вызов таймера и связанный с ним объект buggyObject не будут освобождены до тех пор, пока не истечет таймаут. В этом случае таймер сбрасывается и работает вечно, поэтому его пространство в памяти никогда не будет занято, даже если нет ссылки на исходный объект.

РЕШЕНИЕ: Чтобы избежать этого сценария, придерживайтесь лучших практик JavaScript, предоставляя ссылки внутри вызова setTimeout/setInterval, например, функции должны быть выполнены и завершены, прежде чем их можно будет собирать мусором. Сделайте явный призыв удалить их, как только они вам больше не нужны.

За исключением старых браузеров, таких как Internet Explorers, большинство современных браузеров, таких как Chrome и Firefox, не сталкиваются с этой проблемой. Кроме того, такие библиотеки, как jQuery, обрабатывают это внутри себя, чтобы гарантировать отсутствие утечек памяти в JavaScript.

5. Старые браузеры и расширения с ошибками

Старые браузеры, особенно IE6–7, были печально известны тем, что создавали утечки памяти, поскольку их алгоритм сборщика мусора не мог обрабатывать циклические ссылки между объектами DOM и объектами JavaScript. Иногда причиной утечек могут быть и неисправные расширения браузера. Например, расширение FlashGot в Firefox однажды создало утечку памяти.

6. Слушатели событий

Метод addEventListener() присоединяет обработчик событий к определенному элементу. Вы можете добавить несколько обработчиков событий к одному элементу. Иногда, если элемент DOM и соответствующий ему прослушиватель событий не имеют одинаковый жизненный цикл, это может привести к утечке памяти.

7. Кэши

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

Использование Chrome DevTools для поиска утечек памяти в Javascript

В этом разделе мы узнаем, как использовать Chrome DevTools для выявления утечек памяти JavaScript в вашем коде, используя эти 3 инструмента разработчика:

  1. Просмотр временной шкалы
  2. Профилировщик кучи памяти
  3. Временная шкала распределения (или профилировщик распределения)

Сначала откройте любой редактор кода по вашему выбору, создайте HTML-документ с приведенным ниже кодом и откройте его в браузере Chrome.

<!------ JQuery 3.3.1 ------>
   <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
 
 
 
   <button id="leak-button">Start</button>
   <button id="stop-button">Stop</button>
 
   <script>
       var foo = [];
       function grow() {
           foo.push(new Array(1000000).join('foo'));
           if (running)
               setTimeout(grow, 2000);
       }
       var running = false;
 
       $('#leak-button').click(function () {
           running = true;
           grow();
       });
 
       $('#stop-button').click(function () {
           running = false;
       });
   </script>

При нажатии кнопки «Пуск» будет вызвана функция роста(), которая добавит строку длиной 1000000 символов. Переменная foo — это глобальная переменная, которая не будет подвергаться сборке мусора, поскольку она вызывается функцией роста() рекурсивно каждую секунду. Нажатие кнопки «Стоп» изменит флаг выполнения на false, чтобы остановить рекурсивный вызов функции. Каждый раз, когда вызов функции завершается, сборщик мусора освобождает память, но переменная foo не будет собрана, что приводит к сценарию утечки памяти.

1. Просмотр временной шкалы

Первый инструмент разработчика Chrome, который мы будем использовать для выявления утечек памяти, называется «Временная шкала». Временная шкала — это централизованный обзор активности вашего кода, который помогает вам проанализировать, сколько времени тратится на загрузку, выполнение сценариев, рендеринг и т. д. Вы можете визуализировать утечки памяти, используя опцию записи временной шкалы, и сравнивать данные об использовании памяти до и после сборки мусора.

  • Шаг 1. Откройте наш HTML-документ в браузере Chrome и нажмите Ctrl+Shift+I, чтобы открыть Инструменты разработчика.
  • Шаг 2. Нажмите вкладку «Производительность», чтобы открыть окно обзора временной шкалы. Нажмите Ctrl+E или кнопку записи, чтобы начать запись на временной шкале. Откройте свою веб-страницу и нажмите кнопку «Пуск».
  • Шаг 3: подождите 15 секунд и нажмите кнопку «Стоп» на своей веб-странице. Подождите 10 секунд и нажмите значок мусора справа, чтобы вручную запустить сборщик мусора и остановить запись.

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

2. Профилировщик динамической памяти

«Профилировщик памяти кучи» показывает распределение памяти по объектам JavaScript и связанным узлам DOM. Используйте его для создания снимков кучи, анализа графиков памяти, сравнения данных снимков и поиска утечек памяти.

  • Шаг 1. Нажмите Ctrl+Shift+I, чтобы открыть инструменты разработчика Chrome, и щелкните панель памяти.
  • Шаг 2.Выберите параметр «Снимок кучи» и нажмите «Пуск».

  • Шаг 3. Нажмите кнопку «Пуск» на своей веб-странице и выберите кнопку «Снимок кучи записи» в левом верхнем углу под панелью памяти. Подождите 10–15 секунд и нажмите кнопку закрытия на своей веб-странице. Пройдите вперед и сделайте второй снимок кучи.

  • Шаг 4. выберите в раскрывающемся списке параметр «Сравнение» вместо «Сводка» и найдите отдельные элементы DOM. Это поможет выявить ссылки вне DOM. В нашем примере их нет (утечка памяти в нашем примере связана с глобальной переменной)

3.) График распределения/профилировщик

Профилировщик распределения объединяет информацию моментального снимка профилировщика памяти кучи с инкрементальным отслеживанием панели «Временная шкала». Инструмент периодически делает снимки кучи на протяжении всей записи (каждые 50 мс!) и один последний снимок в конце записи. Изучите сгенерированный график на предмет подозрительного распределения памяти.

В новых версиях Chrome вкладка «Профили» удалена. Теперь вы можете найти инструмент профилировщика распределения внутри панели памяти, а не на панели профилей.

  • Шаг 1. Нажмите Ctrl+Shift+I, чтобы открыть инструменты разработчика Chrome, и щелкните панель памяти.
  • Шаг 2. Выберите параметр «Инструментарий распределения на временной шкале» и нажмите «Пуск».

  • Шаг 3. Нажмите, запишите и подождите, пока профилировщик распределения автоматически будет периодически делать снимки. Проанализируйте созданный график на предмет подозрительного распределения памяти.

симулятор iPhone от LambdaTest позволяет вам легко тестировать ваши веб-сайты и веб-приложения на последних и устаревших устройствах, версиях ОС и браузерах. Вы также можете протестировать свое приложение iOS онлайн на более чем 200 устройствах и средах iOS. Зарегистрируйтесь бесплатно!
https://www.lambdatest.com/ios-simulator-online

Устраняем утечку памяти путем изменения нашего кода

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

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

1. Установите для глобальной переменной foo значение null после того, как она больше не нужна.

2. Используйте «let» вместо «var» для объявления переменной foo. В отличие от var, Let имеет блочную область видимости. Будет вывоз мусора.

3. Поместите переменную foo и объявления функции Grow() в обработчик событий щелчка.

<script>
       var running = false;
 
       $('#leak-button').click(function () {
           /* Variable foo and grow function are now decalred inside the click event handler. They no longer have global scope. They now have local scope and therefore will not lead to memory leak*/
           var foo = [];
 
           function grow() {
               foo.push(new Array(1000000).join('foo'));
               if (running)
                   setTimeout(grow, 2000);
           }
           running = true;
           grow();
       });
 
       $('#stop-button').click(function () {
           running = false;
       });
   </script>

Заключение

Практически невозможно полностью избежать утечек памяти в JavaScript, особенно в больших приложениях. Небольшая утечка не окажет существенного влияния на производительность приложения. Более того, современные браузеры, такие как Chrome и Firefox, оснащенные продвинутыми алгоритмами сборщика мусора, неплохо справляются с автоматическим устранением утечек памяти. Это не означает, что разработчик должен пренебрегать эффективным управлением памятью. Хорошие методы кодирования во многом снижают вероятность утечек прямо на этапе разработки и позволяют избежать осложнений в дальнейшем. Используйте инструменты разработчика Chrome, чтобы выявить как можно больше утечек памяти JavaScript, чтобы обеспечить потрясающий пользовательский опыт без каких-либо зависаний или сбоев.