Обнаружение утечек памяти в приложении Javascript для Windows 8 с помощью инструмента Javascript Memory Analysis из пакета Visual Studio

Язык Javascript прекрасно подходит для разработки приложений для Windows 8. Javascript — нетипизированный динамический язык программирования, обеспечивающий высокую гибкость. Однако без должной внимательности, вы можете допустить утечки памяти в своем коде.

Но вы зря волнуетесь по этому поводу, Visual Studio содержит эффективный инструмент под названием Javascript Memory Analysis, который помогает обнаружить утечки памяти.

image

Рекомендации по применению инструмента Javascript Memory Analysis

Этот инструмент запускается из меню Debug (Отладка) в Visual Studio:

image

После запуска инструмента, запустится и ваше приложение, на экране вы увидите следующее:

image

В первой области окна в режиме реального времени отображается объем памяти, используемой приложением:

image

Ниже присутствует кнопка Take Heap Snapshot (Создание мгновенного снимка кучи), используемая для создания мгновенного снимка «кучи» (элемент управления также показывает размер «кучи» и количество активных объектов):

image

По щелчку на размере «кучи» выводится более подробная информация:

image

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

На примере моего приложения, я вижу, что объект UrzaGatherer удерживает около 60 МБ памяти (так и должно быть, поскольку в нем хранится огромный список карт):

image

Это представление также позволяет вывести на экран:

  • список типов, отсортированный по количеству вхождений;
  • список корневых объектов (с точки зрения сборщика мусора);
  • список объектов DOM, отсортированный по объему удерживаемой памяти;
  • список объектов WinRT, отсортированный по объему удерживаемой памяти.

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

Сравнение моментальных снимков

После каждого нажатия кнопки Take Heap Snapshot (Создание мгновенного снимка кучи) система генерирует новый дамп «кучи» с целью последующего анализа. Кроме того, каждый новый снимок позволяет оценить динамику изменения размера «кучи» и количества объектов.

Это основной инструмент поиска утечек памяти.

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

image

Сравнив два моментальных снимка, я обнаружил, что размер «кучи» увеличился на 6,12 МБ, кроме того, были созданы 53 000 объектов, которые не были в дальнейшем удалены. 

Щелкнув значение, показывающее изменение размера «кучи» (+6,12 МБ), вы можете получить более подробную информацию о различиях между двумя моментальными снимками:

image

Представление Dominators (Доминаторы) показывает, что новые объекты не были удалены после того, как мы вернулись на домашнюю страницу. Это представление поможет вам обнаружить ненужные объекты.

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

image

Как видите, объект удерживается функцией ImportFromTappedOut.

Эта глобальная функция в моем коде принимает функцию в качестве параметра:

 ImportFromTappedOut = function (deckName, custom) {

Параметр custom эта функция использует для вызова специализированного пользовательского кода. Главная проблема связана с тем, что ImportFromTappedOut — глобальная функция, и она хранит весь код, к которому обращается функция, в параметре custom. В этом случае моя анонимная функция ссылается на большое количество локальных объектов DOM:

 Tools.ImportFromTappedOut("test", function () { var select = document.querySelector("#addToDeck"); 
 var count = document.querySelector("#addToDeckCount").value; 
 listView.selection.getItems().then(function (items) { appBar.hide(); 
 appBar.sticky = false; listView.selection.clear();
  
  …code continue… 

Эту проблему мне помог обнаружить рассматриваемый инструмент:

image

Решение простое: достаточно вызвать importFromTappedOut с нулевой функцией, когда я закрываю страницу, чтобы сборщик мусора удалил все сохраненные объекты (в этом случае освободится 1,25 МБ).

Я настоятельно рекомендую вам использовать этот инструмент для выявления и предотвращения утечек памяти. Несмотря на свою простоту, он очень эффективен.

Подробнее о рассматриваемом инструменте

Следующие статьи также могут быть вам полезны: