Анализ и оптимизация запуска приложения

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

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

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

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

Как анализировать и оптимизировать запуск

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

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

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

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

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

  • По возможности перенесите продолжительные операции в фоновый режим. Фоновые процессы могут влиять на загрузку ЦП во время запуска.

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

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

Измеряйте и анализируйте время, затраченное на основные операции

Получив полную трассировку запуска приложения, изучите ее и измерьте время, затраченное на основные операции, такие как bindApplication или activityStart. Для анализа трассировок рекомендуем использовать Perfetto или профилировщики Android Studio.

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

  • Занимают много времени и могут быть оптимизированы. Каждая миллисекунда имеет значение. Например, обратите внимание на время отрисовки Choreographer, время начальной композиции, время загрузки библиотеки, транзакции Binder или время загрузки ресурсов. Для начала посмотрите на все операции, которые занимают больше 20 мс.
  • Блокировка основного потока. Подробнее о том, как работать с отчетом Systrace…
  • Не должны запускаться при запуске.
  • Можно подождать, пока не будет отрисован первый кадр.

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

Как выявить ресурсоемкие операции в основном потоке

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

class MyApplication : Application() {

    override fun onCreate() {
        super.onCreate()

        ...
        if (BuildConfig.DEBUG)
            StrictMode.setThreadPolicy(
                StrictMode.ThreadPolicy.Builder()
                    .detectAll()
                    .penaltyDeath()
                    .build()
            )
        ...
    }
}

Использование StrictMode.ThreadPolicy включает правила потоков во всех отладочных сборках и приводит к сбою приложения при обнаружении нарушений правил потоков, что затрудняет пропуск нарушений правил потоков.

TTID и TTFD

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

Подробнее о том, как повысить точность отчетов о времени запуска…

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

Анализ общего состояния цепочки

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

Такие инструменты, как Android Studio Profiler и Perfetto, предоставляют подробный обзор основного потока и времени, затраченного на каждый этап. Подробную информацию о визуализации трассировок Perfetto можно найти в документации по Perfetto UI.

Определите основные фрагменты состояния сна основного потока

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

Сократите блокировку основного потока и непрерываемый сон

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

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

Ускорить запуск

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

  • Чтобы ускорить TTID, загружайте контент асинхронно и по мере необходимости.
  • Минимизируйте вызовы функций, которые выполняют вызовы связывателя. Если без них не обойтись, оптимизируйте вызовы, кешируя значения, а не повторяя вызовы, или перенесите неблокирующие задачи в фоновые потоки.
  • Чтобы ускорить запуск приложения, вы можете как можно быстрее показать пользователю что-то, что требует минимального рендеринга, пока загружается остальная часть экрана.
  • Создайте и добавьте в приложение профиль запуска.
  • Используйте библиотеку Jetpack App Startup, чтобы оптимизировать инициализацию компонентов при запуске приложения.

Анализ производительности пользовательского интерфейса

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

Ограничьте работу при инициализации

Некоторые фреймы могут загружаться дольше других. Они считаются ресурсоемкими для приложения.

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

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

Измерение данных о кадрах

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

  • Локальный сбор данных с помощью dumpsys gfxinfo. Не все кадры, наблюдаемые в данных dumpsys, ответственны за медленную отрисовку вашего приложения или оказывают какое-либо влияние на конечных пользователей. Однако это хороший показатель, который можно использовать в разных циклах выпуска, чтобы понять общую тенденцию производительности. Подробнее о том, как использовать gfxinfo и framestats для интеграции измерений производительности интерфейса в практику тестирования, рассказывается в статье Основы тестирования приложений для Android.
  • Сбор данных с помощью JankStats Собирайте данные о времени отрисовки кадров в определенных частях приложения с помощью библиотеки JankStats, а затем записывайте и анализируйте их.
  • В тестах с использованием Macrobenchmark (Perfetto)
  • Perfetto FrameTimeline. В Android 12 (уровень API 31) и более поздних версиях можно собирать показатели временной шкалы кадров из трассировки Perfetto, чтобы определить, какие процессы вызывают пропуск кадров. Это может быть первым шагом к диагностике причин пропуска кадров.
  • Профилировщик Android Studio для обнаружения задержек

Проверьте время загрузки основного действия

Основное действие приложения может содержать большой объем информации, загружаемой из нескольких источников. Проверьте интерфейс Activity на главном экране, в частности событие Choreographer#doFrame.

  • Используйте reportFullyDrawn, чтобы сообщить системе, что приложение полностью отрисовано. Это нужно для оптимизации.
  • Измеряйте активность и запуски приложения с помощью StartupTimingMetric и библиотеки Macrobenchmark.
  • Проверьте, не пропускаются ли кадры.
  • Определите макеты, отрисовка или измерение которых занимает много времени.
  • Определите, какие объекты загружаются долго.
  • Определите ненужные элементы пользовательского интерфейса, включенные в исходную композицию.

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

  • Сделайте начальную композицию как можно более легкой. Подробнее о производительности Jetpack Compose…
  • Добавьте собственные контрольные точки, чтобы получить больше информации о пропущенных кадрах и сложных макетах.
  • Минимизируйте количество и размер ресурсов битовых карт, загружаемых при запуске. Подробнее об оптимизации растровых изображений…
  • Если вы используете Jetpack Compose, попробуйте применить условную композицию, чтобы отложить загрузку частей интерфейса, которые не видны сразу после запуска, например экранов ошибок, необязательных сведений или дополнительных вкладок. Обернув тяжелые компоненты простой проверкой состояния, вы избежите выполнения их логики композиции во время критического окна запуска, сохраняя легкость исходного макета.

    var shouldLoad by remember {mutableStateOf(false)}
    
    if (shouldLoad) {
     MyComposable()
    }
    

    Загрузите composable-функции в условный блок, изменив shouldLoad:

    LaunchedEffect(Unit) {
     shouldLoad = true
    }
    

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

    Дополнительную информацию об оптимизации производительности Compose можно найти в разделе Рекомендации.