Обзор измерения производительности приложений

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

Ключевые проблемы с производительностью

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

Задержка при запуске

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

Стремитесь к следующим целям запуска в своих приложениях:

  • Холодный старт менее чем за 500 мс. Холодный старт происходит, когда запускаемое приложение отсутствует в памяти системы. Это происходит, когда это первый запуск приложения после перезагрузки или когда процесс приложения остановлен пользователем или системой.

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

  • Задержки P95 и P99 очень близки к средней задержке. Когда приложению требуется много времени для запуска, это ухудшает взаимодействие с пользователем. Межпроцессные коммуникации (IPC) и ненужный ввод-вывод на критическом пути запуска приложения могут привести к конфликту блокировок и привести к несогласованности.

Прокрутка

Джанк — это термин, описывающий визуальный сбой, который возникает, когда система не может вовремя создавать и предоставлять кадры, чтобы отобразить их на экране с запрошенной частотой 60 Гц или выше. Подвисания наиболее заметны при прокрутке, когда вместо плавно анимированного потока возникают икоты. Джанк появляется, когда движение приостанавливается на один или несколько кадров, поскольку приложению требуется больше времени для рендеринга контента, чем продолжительность кадра в системе.

Приложения должны поддерживать частоту обновления 90 Гц. Обычная частота рендеринга составляет 60 Гц, но многие новые устройства работают в режиме 90 Гц во время взаимодействия с пользователем, например при прокрутке. Некоторые устройства поддерживают еще более высокие частоты — до 120 Гц.

Чтобы узнать, какую частоту обновления использует устройство в данный момент, включите наложение, выбрав «Параметры разработчика» > «Показать частоту обновления» в разделе «Отладка» .

Переходы, которые не являются плавными

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

Энергетическая неэффективность

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

Выделение памяти, возникающее в результате создания новых объектов в коде, может стать причиной значительной работы в системе. Это связано с тем, что не только сами выделения требуют усилий со стороны Android Runtime (ART), но и последующее освобождение этих объектов ( сборка мусора ) также требует времени и усилий. И выделение, и сбор происходят намного быстрее и эффективнее, особенно для временных объектов. Хотя раньше было лучше избегать выделения объектов, когда это возможно, мы рекомендуем вам делать то, что наиболее целесообразно для вашего приложения и архитектуры. Экономия на выделении ресурсов с риском получить неподдерживаемый код — не лучшая практика, учитывая возможности ART.

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

Выявление проблем

Мы рекомендовали следующий рабочий процесс для выявления и устранения проблем с производительностью:

  1. Определите и проверьте следующие критические пути пользователя:
    • Общие процессы запуска, в том числе из панели запуска и уведомлений.
    • Экраны, на которых пользователь прокручивает данные.
    • Переходы между экранами.
    • Длительные процессы, такие как навигация или воспроизведение музыки.
  2. Проверьте, что происходит во время предыдущих потоков, используя следующие инструменты отладки:
    • Perfetto : позволяет видеть, что происходит на всем устройстве, с точными данными о времени.
    • Профилировщик памяти : позволяет увидеть, какое распределение памяти происходит в куче.
    • Simpleperf : показывает график того, какие вызовы функций используют больше всего процессора в течение определенного периода времени. Если вы обнаружите в Systrace что-то, что занимает много времени, но не знаете, почему, Simpleperf может предоставить дополнительную информацию.

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

  • Потоки запуска
  • Джанк
    • Метрики поля
      • Основные сведения о фрейме Play Console: в Play Console вы не можете сузить показатели до конкретного пути пользователя. Он сообщает только об общем сбое во всем приложении.
      • Пользовательское измерение с помощью FrameMetricsAggregator : вы можете использовать FrameMetricsAggregator для записи показателей ошибок во время определенного рабочего процесса.
    • Лабораторные тесты
      • Прокрутка с помощью Macrobenchmark .
      • Macrobenchmark собирает время кадра с помощью команд dumpsys gfxinfo , которые ограничивают одно взаимодействие пользователя. Это способ понять разницу в трафике в зависимости от пути пользователя. Метрики RenderTime , которые показывают, сколько времени занимает прорисовка кадров, более важны, чем количество некачественных кадров, для выявления регрессов или улучшений.

Ссылки на приложения — это глубокие ссылки, основанные на URL-адресе вашего веб-сайта, принадлежность которых подтверждена к вашему веб-сайту. Ниже приведены причины, которые могут привести к сбою проверки App Link.

  • Области фильтра намерений: добавляйте autoVerify в фильтры намерений только для URL-адресов, на которые ваше приложение может реагировать.
  • Непроверенные переключатели протоколов: непроверенные перенаправления на стороне сервера и поддомена считаются угрозой безопасности и не проходят проверку. Они приводят к сбою всех ссылок autoVerify . Например, перенаправление ссылок с HTTP на HTTPS, таких как example.com на www.example.com, без проверки ссылок HTTPS может привести к сбою проверки. Обязательно проверьте ссылки на приложения, добавив фильтры намерений.
  • Непроверяемые ссылки: добавление непроверяемых ссылок в целях тестирования может привести к тому, что система не будет проверять ссылки на ваше приложение.
  • Ненадежные серверы: убедитесь, что ваши серверы могут подключаться к вашим клиентским приложениям.

Настройте свое приложение для анализа производительности

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

Точки трассировки

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

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

Рекомендации по APK

Варианты отладки могут быть полезны для устранения неполадок и обозначения образцов стека, но они серьезно влияют на производительность. Устройства под управлением Android 10 (уровень API 29) и выше могут использовать profileable android:shell="true" в своем манифесте, чтобы включить профилирование в сборках выпуска.

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

Сборник

Скомпилируйте приложение на устройстве до известного состояния — обычно speed для простоты или speed-profile для более точного соответствия производительности (хотя для этого требуется прогрев приложения и создание дампа профилей или компиляция базовых профилей приложения).

И speed , и speed-profile уменьшают объем выполняемого кода, интерпретируемого из dex, и, следовательно, объем фоновой JIT-компиляции, которая может вызвать значительные помехи. Только speed-profile снижает влияние загрузки классов во время выполнения из dex.

Следующая команда компилирует приложение в speed режиме:

adb shell cmd package compile -m speed -f com.example.packagename

Режим speed компиляции полностью компилирует методы приложения. В режиме speed-profile методы и классы приложения компилируются в соответствии с профилем используемых путей кода, который собирается во время использования приложения. Собирать профили последовательно и правильно может быть сложно, поэтому, если вы решите их использовать, убедитесь, что они собирают то, что вы ожидаете. Профили расположены по следующему адресу:

/data/misc/profiles/ref/[package-name]/primary.prof

Системные соображения

Для низкоуровневых и высокоточных измерений откалибруйте свои устройства. Запустите сравнения A/B на одном устройстве и той же версии ОС. Производительность может существенно различаться даже на устройствах одного и того же типа.

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

  • Разместите процессоры на фиксированной частоте.
  • Отключите малые ядра и настройте графический процессор.
  • Отключите термическое регулирование.

Мы не рекомендуем использовать сценарий lockClocks для тестов, ориентированных на взаимодействие с пользователем, таких как запуск приложений, тестирование DoU и тестирование ошибок, но это может быть важно для снижения шума в тестах Microbenchmark.

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

Медленный запуск приложения: ненужная активность на батуте

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

alt_text Рисунок 1. След, показывающий активность батута.

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

Ненужные выделения, вызывающие частые GC

Вы можете заметить, что в Systrace сборка мусора (GC) происходит чаще, чем вы ожидаете.

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

alt_text Рисунок 2. Трассировка, показывающая пространство между событиями GC.

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

Джанки кадры

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

Когда кадры отрисовываются без особых усилий со стороны приложения, точки трассировки Choreographer.doFrame() возникают с частотой 16,7 мс на устройстве с частотой 60 кадров в секунду:

alt_text Рисунок 3. Трассировка, показывающая частые быстрые кадры.

Если вы уменьшите масштаб и проведете по трассировке, вы иногда увидите, что обработка кадров занимает немного больше времени, но это все равно нормально, поскольку они не занимают больше отведенного времени 16,7 мс:

alt_text Рисунок 4. Трассировка, показывающая частые быстрые кадры с периодическими всплесками работы.

Когда вы видите нарушение регулярного ритма, это неровный кадр, как показано на рисунке 5:

alt_text Рисунок 5. Трассировка, показывающая неровный кадр.

Вы можете попрактиковаться в их выявлении.

alt_text Рисунок 6. Трассировка, показывающая более неровные кадры.

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

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

Распространенные ошибки RecyclerView

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

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

Если вы не поддерживаете каждый вложенный RecyclerView должным образом, это может привести к тому, что внутренний RecyclerView каждый раз будет полностью воссоздаваться. Каждый вложенный внутренний RecyclerView должен иметь набор RecycledViewPool , чтобы гарантировать возможность повторного использования представлений между каждым внутренним RecyclerView .

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

Отладка вашего приложения

Ниже приведены различные методы отладки производительности вашего приложения. В следующем видео представлен обзор системной трассировки и использования профилировщика Android Studio.

Отладка запуска приложения с помощью Systrace

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

Устранить неоднозначность типов запуска можно на следующих этапах:

  • Холодный запуск: начните с создания нового процесса без сохраненного состояния .
  • Теплый запуск: либо воссоздает действие при повторном использовании процесса, либо воссоздает процесс с сохраненным состоянием.
  • Горячий запуск: перезапускает деятельность и начинается с инфляции.

Мы рекомендуем захватывать Systraces с помощью приложения System Tracing на устройстве . Для Android 10 и выше используйте Perfetto . Для Android 9 и более ранних версий используйте Systrace . Мы также рекомендуем просматривать файлы трассировки с помощью веб-просмотра трассировки Perfetto . Дополнительные сведения см. в разделе Обзор трассировки системы .

Вот некоторые вещи, на которые стоит обратить внимание:

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

  • Параллельный сбор мусора: это распространенное явление, оказывающее относительно небольшое влияние, но если вы сталкиваетесь с этим часто, рассмотрите возможность изучения этого с помощью профилировщика памяти Android Studio.

  • Ввод-вывод: проверьте ввод-вывод, выполняемый во время запуска, и обратите внимание на длительные остановки.

  • Значительная активность в других потоках: они могут мешать потоку пользовательского интерфейса, поэтому следите за фоновой работой во время запуска.

Мы рекомендуем вызывать reportFullyDrawn после завершения запуска с точки зрения приложения, чтобы улучшить отчеты о показателях запуска приложения. Дополнительную информацию об использовании reportFullyDrawn см. в разделе « Время до полного отображения» . Вы можете извлечь время начала, определенное RFD, с помощью процессора трассировки Perfetto, и будет создано видимое пользователю событие трассировки.

Используйте трассировку системы на устройстве

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

Используйте профилировщик памяти Android Studio

Вы можете использовать профилировщик памяти Android Studio для проверки нехватки памяти, которая может быть вызвана утечками памяти или неправильным использованием. Он обеспечивает просмотр распределения объектов в реальном времени.

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

Чтобы профилировать память приложения, выполните следующие действия:

  1. Обнаружение проблем с памятью.

    Запишите сеанс профилирования памяти о пути пользователя, на котором вы хотите сосредоточиться. Следите за увеличением количества объектов, как показано на рисунке 7, что в конечном итоге приводит к появлению сборщиков мусора, как показано на рисунке 8.

    alt_text Рисунок 7. Увеличение количества объектов.

    alt_text Рисунок 8. Сборки мусора.

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

  2. Диагностика «горячих точек» нехватки памяти.

    Выберите диапазон на временной шкале, чтобы визуализировать Распределение и Небольшой размер , как показано на рисунке 9.

    alt_text Рисунок 9. Значения для выделений и небольшого размера .

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

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

      Например, если вы видите, что приложение каждую секунду создает 2000 объектов класса Vertex, оно увеличивает количество выделений на 2000 каждую секунду, и вы видите это при сортировке по классу. Если вы хотите повторно использовать эти объекты, чтобы избежать создания мусора, реализуйте пул памяти.

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

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

    • Сохраненный размер : показывает общий объем памяти, принадлежащий объекту, и ссылкам, на которые ссылается только объект. Это полезно для отслеживания нехватки памяти из-за сложных объектов. Чтобы получить это значение, создайте полный дамп памяти, как показано на рисунке 10, и добавьте в столбец Retained Size , как показано на рисунке 11.

      alt_text Рисунок 10. Полный дамп памяти.

      Столбец «Сохраненный размер».
      Рисунок 11. Столбец «Сохраненный размер».
  3. Измерьте влияние оптимизации.

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

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

    Конечные результаты улучшения памяти заключаются в следующем:

    • Количество отключений из-за нехватки памяти, вероятно, уменьшится, если приложение не будет постоянно испытывать нехватку памяти.
    • Меньшее количество GC улучшает показатели мусора, особенно в P99. Это связано с тем, что сборщики мусора вызывают конфликт ЦП, что может привести к отсрочке задач рендеринга во время выполнения сборщика мусора.
{% дословно %} {% дословно %} {% дословно %} {% дословно %}