Утечки памяти в мобильных приложениях: руководство для QA-инженеров |
10.07.2024 00:00 |
Меня зовут Ира и я руковожу отделом тестирования мобильной платформы: наш отдел занимается разработкой инструментов для автоматизации тестирования мобильных приложений Ozon и тестированием внутренних библиотек, которые используются в наших приложениях. Около года назад мы пытались понять, почему у одной из команд джоба с автотестами отваливается по тайм-ауту. К слову, это был проект мобильного приложения для продавцов, и на нем у нас для автоматизации тестирования используются нативные фреймворки: Kaspresso + Kotlin для Android и XCTest + Swift для iOS. Одна из гипотез заключалась в том, что в приложении могут быть утечки памяти и что-то зависает. Спойлер: дело было не в этом. В общем, около года назад я проверяла, что к чему там у нас с памятью приложения, а сейчас поняла, что полученными знаниями можно и поделиться. Эта статья будет полезна тем, кто только начинает изучать, что происходит со стабильностью мобильного приложения. Внутри статьи разберёмся с тем, как приложение работает с оперативной памятью; что такое утечки памяти и когда они возникают; как утечки влияют на стабильность работы приложения и как их находить. Как исправлять найденные проблемы в своей статье я не описываю. Введение Представьте, что запускаете мобильное приложение, в котором много полезных фич и интересных возможностей. Но вместо того, чтобы наслаждаться его работой, сталкиваетесь с внезапным завершением работы приложения, с зависаниями приложения и медленным откликом после нажатия на элементы. Одна из возможных причин такого поведения — это утечки памяти. Утечка памяти (memory leak) — это состояние, когда приложение использует оперативную память устройства и не освобождает её после завершения своей работы. Такое состояние может наступать по разным причинам, включая ошибки в коде приложения, некорректное управление жизненным циклом объектов, утечки ресурсов или неправильное использование сторонних библиотек. Использование оперативной памяти во время работы с мобильным приложениемПрежде чем перейти к поиску и анализу проблем, вызываемых утечками памяти, разберёмся, какая память есть в смартфоне и что происходит с памятью, когда пользователь работает с мобильным приложением. В смартфонах обычно используется несколько видов памяти:
В этой статье нас интересует только оперативная память (RAM), далее — память. Когда запускается мобильное приложение, для него выделяется место в памяти. После инициализации приложение начинает загрузку данных с сервера, обработку пользовательского ввода, выполнение алгоритмов и т. д. Каждая операция требует временного использования памяти для хранения промежуточных результатов и переменных. Также оперативная память активно используется операционной системой для управления переходами между экранами и обеспечения плавной работы мобильного приложения. Операционная система отслеживает жизненный цикл каждого экрана (Activity или Fragment в Android, ViewController или View в iOS) и использует оперативную память для сохранения состояния экрана в случае необходимости. Например, если пользователь переходит на другой экран и затем возвращается, состояние экрана может быть восстановлено из памяти. При необходимости операционная система может освобождать память, занимаемую предыдущим экраном, который больше не отображается на экране. Это может включать в себя удаление из памяти временных объектов и освобождение ресурсов, чтобы освободить место для нового экрана. Некоторые данные могут быть сохранены в памяти на время перехода между экранами, чтобы обеспечить плавный переход. Например, если пользователь вводил данные в форме на одном экране, эти данные могут временно сохраняться в памяти, чтобы не потеряться при переходе к следующему экрану. Когда приложение завершает свою работу, связанный с ним процесс также завершается. Это означает, что все выделенные для этого процесса ресурсы, включая оперативную память, освобождаются и возвращаются в систему. Допустим, у нас есть два экрана: «Товары» со списком товаров и «Настройки» с настройками приложения. Попробую нарисовать схематично, что происходит, когда запускается приложение и происходит переход по экранам. На картинке выше зелёным цветом отмечена область в памяти, которая всегда должна быть выделена для корректной работы приложения в любой момент времени. Жёлтым цветом отмечены те области, в которых есть данные, некритичные для работы всего приложения (скорее всего, пользователю не нужна информация с экрана Товаров, когда он находится в Настройках приложения, и данные Товаров можно удалить). Если выделенная изначально под наше приложение область в памяти будет заполнена, приложение может запросить у операционной системы дополнительный ресурс. Однако этот ресурс ограничен техническими характеристиками смартфона. Поэтому важно своевременно удалять неиспользуемые данные из памяти. Это можно делать из кода приложения: разработчик может управлять тем, что и когда размещать в оперативной памяти и когда удалять из неё ненужные объекты. И как раз в этом месте могут возникать ошибки. Самые распространённые из них — это утечки памяти. Типичные баги, связанные с утечками памяти
Ниже приведу примеры возможных тест-кейсов для поиска проблем с утечками памяти, но сначала познакомимся с инструментами, которые помогут их обнаружить. Самый простой путь — это поискать ошибку OutOfMemoryError в логах и приложить найденные логи к тикету. Или можно посмотреть производительность приложения самостоятельно в режиме реального времени. Для этого используются профилировщики. Профилировщик — это инструмент разработки программного обеспечения, который позволяет анализировать производительность приложения и выявлять узкие места в его работе. Он используется для сбора информации о времени выполнения различных частей программы, использовании памяти, вызовах функций и других аспектах работы приложения. Для Android-приложений есть профилировщик внутри Android Studio или можно подключить к проекту библиотеку LeakCanary. Для iOS обычно используется Xcode Instruments. Про то, как пользоваться профилировщиками, написано уже много статей, поэтому не буду их пересказывать здесь, добавлю просто ссылки в конце своей статьи (в следующем разделе будут скриншоты того, что можно увидеть в профилировщике). Наконец разберёмся, что можно делать, чтобы воспроизвести баг с утечкой памяти в мобильном приложении. Важно отметить, что утечки начинают влиять на приложение, когда пользователь долго сидит в приложении, и это даёт возможность накопиться большому количеству утечек, что может вызвать проблемы в совершенно любом месте приложения. То есть возможна ситуация, когда утечка происходит на одном экране (например, экран со списком Товаров), и в фоне память утекает; потом мы переходим на другой экран (например, экран Настроек приложения) и происходит вылет. Поэтому такие баги сложно поймать и локализовать: обычно нет чёткого сценария воспроизведения.
В «ожидаемом результате» указываю результат, который можно увидеть в профилировщике. Смотрим утечки памяти на Android
Android ProfilerЭто встроенный инструмент Android Studio для разработки приложений под Android. Он предоставляет информацию о производительности приложения, включая использование памяти, CPU и сетевых ресурсов. Запускаю debug-сборку на девайсе Poco X3 Pro. На скриншотах ниже можно увидеть общую информацию по использованию памяти приложением и список Activity и Fragment’ов, где потенциально могут быть проблемы в работе с памятью. LeakCanaryЭто библиотека для обнаружения утечек памяти в приложениях на платформе Android. Она автоматически анализирует утечки памяти и отправляет уведомления в случае обнаружения утечек, а также предоставляет подробные отчёты об утечках памяти с указанием места возникновения проблемы в коде. Запускаю приложение с внедрённой библиотекой LeakCanary (и открываю полученные дампы в Android Studio): Здесь интересно, что одна из утечек возникала в LeakActivity — а это Activity из библиотеки LeakCanary :) ЗаключениеПри тестировании приложения мы тщательно проверяем UI/UX, логику, обработку ошибок, которые приходят с сервера, загрузку картинок и много ещё всего, что пользователь может легко увидеть глазами, но не всегда думаем про стабильность нашего приложения. При этом, допуская наличие утечек памяти в приложении, мы рискуем вызвать сильный негатив у пользователя во время использования приложения, несмотря на полезный функционал и красивый интерфейс. Надеюсь, эта статья помогла лучше понять, какие проблемы со стабильностью могут возникать в мобильном приложении и как их отловить. Что ещё можно почитать
|