[Перевод] Fuite — инструмент для поиска утечек памяти в SPA

Отладка утечек памяти в веб-приложениях — сложная задача. Инструменты существуют, но они сложны, громоздки и часто не дают ответа на простой вопрос: почему у моего приложения происходит утечка памяти?

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

Когда я впервые начал изучать утечки памяти, я подумал, что это редкость. Как может JavaScript — язык с автоматическим сборщиком мусора — стать большим источником утечек памяти? Но чем больше я узнавал, тем больше подозревал, что утечки памяти на самом деле довольно часты в одностраничных приложениях (SPA) — просто никто не проверяет это!

Поскольку большинство веб-разработчиков не возятся с инструментами памяти Chrome для удовольствия, они, вероятно, не заметят утечки, пока вкладка браузера не выйдет из строя с ошибкой Out Of Memory, или страница не замедлится, или кто-то случайно не откроется. Откройте диспетчер задач и обратите внимание, что веб-сайт использует много мегабайт (или даже гигабайт!) памяти. Но в этот момент все стало настолько плохо, что на одной странице может быть несколько утечек.

Я уже писал об утечках памяти в прошлом, но мой совет в основном сводится к следующему: «Используйте Chrome DevTools, выполните эту дюжину утомительных шагов, и тогда, возможно, вы сможете выяснить, почему ваша страница протекает». Это не лучший опыт для разработчиков, и я уверен, что многие читатели в отчаянии покачали головами и продолжали. Было бы намного лучше, если бы инструмент мог автоматически обнаруживать утечки памяти.

Вот почему я написал fuite (по-французски «утечка»). fuite— это инструмент командной строки, который можно указать на любой URL-адрес, и он будет анализировать страницу на предмет утечек памяти:

npx fuite >

Вот и все! По умолчанию он предполагает, что сайт является клиентским SPA, и будет сканировать страницу на предмет внутренних ссылок (таких как /aboutили /contact). Затем для каждой ссылки выполняются следующие шаги:

  1. Нажмите на ссылку

  2. Нажмите кнопку назад в браузере

  3. Повторите, чтобы увидеть, растет ли память

При fuiteобнаружении утечек он покажет, какие объекты предположительно вызывают утечку:

image-loader.svg

Для этого fuiteиспользуется базовая стратегия, изложенная в моем сообщении в блоге. Это запустит Chrome, запустить некоторый сценарий п число раз (7 по умолчанию) и посмотреть , если какие — либо объекты утечки кратно п раз (7, 14, 21 и т.д.).

fuiteтакже проанализирует любые массивы, объекты, карты, наборы, прослушиватели событий и общую модель DOM, чтобы увидеть, не происходит ли утечка каких-либо из них. Например, если массив увеличивается ровно на 7 после 7 итераций, вероятно, он протекает.

Тестирование реальных веб-сайтов

Несколько удивительно, что «базового» сценария перехода по внутренним ссылкам и нажатия кнопки «Назад» достаточно, чтобы обнаружить утечки памяти во многих SPA. Я протестировал fuite на домашних страницах 10 популярных интерфейсных фреймворков и обнаружил утечки во всех из них:

image-loader.svg

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

Чтобы подтвердить эти результаты самостоятельно, вы можете использовать вкладку Chrome DevTools Memory. Вот снимок экрана с худшим сайтом из моего набора, где я нажимаю ссылку, нажимаю кнопку возврата, делаю heap snapshot и повторяю:

image-loader.svg

На этом конкретном сайте объем памяти увеличивается примерно на 6 МБ каждый раз, когда вы переходите по ссылке и возвращаетесь.

Чтобы избежать имен и позора, я не перечислил фактические веб-сайты. Дело в том, чтобы показать репрезентативную выборку некоторых популярных SPA — авторы этих веб-сайтов могут самостоятельно запускать fuiteи отслеживать эти утечки. (Пожалуйста, сделайте это!)

Предостережения

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

Некоторый рост памяти также может быть связан с внутренними изменениями браузера (такими как JITing), которые веб-страница не может контролировать. Таким образом, цифры роста памяти — несовершенная мера того, что вы можете получить от устранения утечек — вполне может быть, что прирост на несколько килобайт неизбежен. (Хотя fuiteпытается игнорировать внутренний рост браузера и будет говорить «утечки обнаружены» только в том случае, если есть действенный совет для веб-разработчика.)

В редких случаях некоторый рост памяти также может быть связан с явными ошибками браузера. Анализируя сайты выше, я действительно нашел один (Сайт №4), который, похоже, страдает от этой ошибки Chrome из-за того, что не выгружается. К сожалению, fuiteобнаружить ошибки браузера будет сложно , поэтому, если вы озадачены утечкой, рекомендуется провести перекрестную проверку с другими браузерами!

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

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

fuiteв настоящее время измеряется только память кучи JavaScript в основном фрейме страницы, поэтому кросс-исходные фреймы, веб-воркеры и сервисные воркеры не измеряются. Что-то вроде [performance.measureUserAgentSpecificMemory()]()было бы более точным, но это доступно только в изолированных контекстах с перекрестным происхождением , поэтому сейчас это непрактично для универсального инструмента.

Другие сценарии утечки памяти

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

  • Откройте модальное диалоговое окно, а затем закройте его

  • Наведите указатель мыши на элемент, чтобы отобразить всплывающую подсказку, затем наведите курсор мыши, чтобы закрыть его

  • Прокрутите список с бесконечной загрузкой, затем переходите назад и назад

  • И Т. Д.

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

Для анализа утечек fuiteзахватывает файлы моментальных снимков кучи , которые вы можете загрузить в Chrome DevTools для проверки. В нем также есть --debugрежим, который можно использовать для более детального анализа: пошаговое выполнение теста во время его выполнения, отладка браузера в режиме реального времени, анализ утечек объектов и т. Д.

Под капотом fuiteэто довольно простой инструмент, и я не буду утверждать, что он может выполнять 100% работы по устранению утечек памяти. По-прежнему существует человеческий компонент — выяснить, почему ваши объекты были выделены и сохранены, а затем найти разумное решение. Но моя цель состоит в том, чтобы автоматизировать ~ 95% работы, так что это на самом деле становится достижимой утечек затруднительное памяти в веб — приложениях.

Выражаю огромную благодарность моей жене за помощь в подготовке перевода

© Habrahabr.ru