Cold Start — холодний запуск та оптимізація в Android

Автор: IT Sectr Опубліковано: 2026-03-31 Час читання: 9 хв

Cold Start — це повний цикл запуску Android-застосунку, що починається з нульового стану, коли процес застосунку не існує в пам’яті, а Activity не створювалася. Система створює новий процес, завантажує класи, ініціалізує Application, створює Activity та виконує перше відображення. За даними Google, 2024, холодний запуск на пристроях середнього сегмента може займати від 1 до 5 секунд, і кожні 100 мс затримки знижують ймовірність утримання користувача на 3%.

Головне

  • Cold Start — запуск застосунку Android з нуля: новий процес, завантаження класів, ініціалізація
  • Метрика вимірюється від старту процесу до першого відображення (TTID або TTFD)
  • Етапи старту: створення процесу → Application.onCreate → Activity.onCreate → перший кадр
  • Оптимізація включає ліниву ініціалізацію, Baseline Profiles та зменшення розміру DEX
  • Google Play використовує Cold Start як один із ключових показників в Android Vitals

Що таке Cold Start

Cold Start (холодний запуск) — це сценарій, при якому Android-застосунок запускається з найпочатковішого стану: операційна система створює новий процес (fork з Zygote), виділяє пам’ять, завантажує DEX-код в ART, ініціалізує класи та створює екземпляр Application, а потім першу Activity. До запуску застосунку жодних даних про нього в пам’яті пристрою немає, крім кешованих образів класів, якщо використовується Background Dexopt.

Коли відбувається Cold Start

Холодний запуск відбувається в трьох випадках: при першому запуску після встановлення застосунку, при запуску після перезавантаження пристрою та при запуску після того, як система вивантажила процес через нестачу пам’яті. На пристроях з 2–4 ГБ ОЗП система вивантажує фонові процеси досить агресивно, тому Cold Start може відбуватися при кожному поверненні до застосунку через кілька годин простою. В Android 12+ система може зберігати заморожений процес (freeze / cached), але при активній економії пам’яті (OOM-killer) процес буде знищено.

Чому Cold Start — критична метрика

За даними Google (звіт Find My Device, 2023), 65% користувачів закривають застосунок, якщо він не відкривається за 3 секунди. Для соціальних мереж і месенджерів, де користувач повертається десятки разів на день, Cold Start безпосередньо впливає на утримання. В Google Play Console метрика Cold Start входить до розділу Android Vitals і відображається як один із показників ANR та продуктивності. Застосунок, що перевищує поріг “поганого” Cold Start (більше 5 секунд на 25% пристроїв), отримує попередження в консолі та може бути знижений у пошуку.

Cold Start vs Warm Start vs Hot Start

Android розрізняє три типи запуску застосунку, кожен з яких має різну тривалість, вплив на UX та підходи до оптимізації. Розуміння різниці необхідне для вибору правильної стратегії профілювання.

Тип запускуСтан процесуApplication.onCreateТиповий час
ColdНемає процесуВиконується1–5 секунд
WarmПроцес є, Activity немаєНе виконується200–600 мс
HotПроцес + Activity в пам’ятіНе виконується< 200 мс

Warm Start відбувається, коли процес застосунку вже існує в фоні, але Activity була знищена (наприклад, користувач повернувся після довгої паузи, і система звільнила пам’ять Activity). Hot Start — коли користувач згортає застосунок і одразу відкриває його знову: Activity призупинена і відновлення займає мінімальний час. Для користувача Cold Start — найпомітніший тип запуску, саме його оптимізація дає найбільший приріст у UX.

Перехід між типами

Cold Start може стати Warm Start після того, як застосунок було запущено хоча б один раз — ART кешує скомпільовані образи класів (Image в Boot Profile) і повторне завантаження DEX відбувається швидше. Тому другий запуск після першого Cold Start зазвичай на 20–40% швидший. Якщо застосунок використовує Baseline Profiles, профілі завантажуються при першому запуску і другий старт може бути ще швидшим: Google Play, що опублікував Baseline Profiles, прискорив Cold Start на 30% на пристроях з Android 12+.

Фази холодного запуску

Cold Start складається зі строго визначених фаз, кожна з яких може бути виміряна та оптимізована незалежно. Знання фаз допомагає визначити, на якому етапі застосунок втрачає час. Google виділяє чотири основні фази: створення процесу, ініціалізація Application, створення Activity та перший кадр.

Фаза 1: Створення процесу (fork)

Система Android (ActivityManagerService) створює новий процес шляхом fork з процесу Zygote. Zygote — це попередньо завантажений процес з common-класами Android. Fork виконується за 30–80 мс — це час, який застосунок не може контролювати. Після fork запускається ActivityThread — екземпляр головного циклу застосунку. На цьому етапі також відбувається завантаження класів через ClassLoader, і ART починає інтерпретувати перший байт-код. Якщо застосунок використовує багато статичних ініціалізаторів, ця фаза може затягнутися.

Фаза 2: Application.onCreate

Відразу після старту ActivityThread викликається Application.onCreate. Тут розробник найчастіше робить помилку, ініціалізуючи все одразу: Crashlytics, Firebase, мережеві клієнти, бази даних, Dagger-компоненти, DI-контейнери. Кожна така ініціалізація — це час, заблокований на головному потоці. Якщо Application.onCreate виконується 500 мс, усі ці півсекунди користувач бачить білий (або чорний) екран. Оптимальна тривалість цієї фази — менше 200 мс на середньому пристрої.

Фаза 3: Activity.onCreate

Після ініціалізації Application створюється екземпляр Activity (MainActivity або Launcher Activity). Викликається Activity.onCreate, де відбувається setContentView, ініціалізація фрагментів, налаштування ViewModel, підписка на LiveData/Flow. Якщо onCreate виконує завантаження даних (SharedPreferences, SQLite, API) синхронно на головному потоці, фаза розширюється. Мета — вкластися в 200–400 мс на середньому пристрої.

Фаза 4: Перший кадр (TTFD)

Після завершення onCreate починається перше відображення: міра, лейаут, draw. Цей момент називається TTFD (Time To First Draw). Якщо застосунок використовує splash-екран (через SplashScreen API на Android 12+ або через theme), відображення може відбутися швидше, але користувач все одно чекатиме, поки splash зникне. Ідеальний TTFD для Cold Start — менше 1.5 секунди.

Як виміряти Cold Start

Вимірювання Cold Start потребує спеціальних інструментів, оскільки звичайне логування (Log.d) починає роботу лише після створення Application, а таймінг fork та завантаження класів залишається недоступним. Google рекомендує три методи: ADB-команди, Android Vitals та кастомні макроси продуктивності.

Вимірювання через ADB

Найпростіший і відтворюваний спосіб — команда adb shell am start -S -W. Прапорець -S примусово зупиняє застосунок перед запуском (гарантує Cold Start). Команда виводить три метрики: ThisTime (час старту Activity), TotalTime (сумарний час з урахуванням запуску процесу) та WaitTime (час з урахуванням усіх затримок Activity Manager). Для чистоти вимірювання зробіть 5–7 замірів та візьміть медіану — поодинокі заміри піддаються шуму (CPU throttling, фонове навантаження).

bash
# Примусовий Cold Start з заміром
$ adb shell am start -S -W \
    com.example.app/.MainActivity

# Вивід команди:
# ThisTime: 1842 ms
# TotalTime: 1842 ms
# WaitTime: 1855 ms

Android Vitals (Google Play Console)

Google Play Console збирає анонімні метрики з усіх пристроїв, де встановлено застосунок. У розділі Android Vitals → Launch time відображається медіанний розподіл Cold Start за моделлю пристрою та версією Android. Це єдиний спосіб побачити реальні показники на пристроях користувачів, а не на тестових девайсах. Якщо на Redmi 9A (2 ГБ ОЗП) Cold Start перевищує 5 секунд, а на Pixel 8 — 1.2 секунди, проблема в обсязі пам’яті та кількості класів. Google також показує користувацьку сприйману затримку на основі 25 перцентиля.

Macrobenchmark

Google Jetpack Macrobenchmark (бібліотека androidx.benchmark) дозволяє писати інструментовані тести запуску застосунку. Тест встановлює застосунок, запускає його з холодним станом і вимірює час до першого кадру. Macrobenchmark автоматично робить 20 прогонів, відкидає викиди та показує стабільні процентилі. Для CI/CD можна порівняти baseline та поточний запуск — якщо час збільшився, CI-пайплайн може падати.

Як оптимізувати Cold Start

Оптимізація Cold Start — це системна робота, що зачіпає кілька рівнів застосунку: код, ресурси, конфігурацію збірки та архітектуру ініціалізації. Google рекомендує починати з найдорожчого — Application.onCreate — і рухатися до дрібниць.

Лінива ініціалізація (Lazy Init)

Перенесіть всю ініціалізацію, що не потрібна на старті, з Application.onCreate у першу точку використання. Firebase, Crashlytics, analytics SDK, push-notifications, DI-компоненти — все можна ініціалізувати після відображення першого екрана. Використовуйте Lazy (by lazy) в Kotlin або ContentProvider-ініціалізацію з явним викликом initialize(context). За даними Google (Android Performance, 2023), лінива ініціалізація скорочує Cold Start на 40–60% для застосунків, що використовують 5+ SDK.

Baseline Profiles

Baseline Profiles — це AOT-компіляція критичних класів та методів, що використовуються на старті застосунку. Без Baseline Profiles ART інтерпретує DEX-код або компілює його JIT, що займає час. З профілями ART компілює зазначені методи в нативний код (AOT) при встановленні застосунку. Google стверджує, що Baseline Profiles дають прискорення Cold Start на 15–40% на Android 9+ і до 60% з ART-оптимізаціями Android 12+. Для створення профілів використовуйте плагін androidx.benchmark:benchmark-baseline-profile-gradle-plugin.

App Startup Library

Бібліотека androidx.startup дозволяє впорядкувати ініціалізацію компонентів та виконувати її в одному ContentProvider. Замість кількох ContentProvider’ів від різних бібліотек (кожен додає 1–2 мс до холодного старту) App Startup об’єднує їх у граф залежностей та ініціалізує строго за необхідністю. На старті виконуються лише компоненти з @Initializer, позначені як необхідні для першого екрана. Для решти встановлюється прапорець needEarlyInit = false — вони запускаються після першого відображення.

kotlin
// App Startup Initializer — ініціалізація після старту
class AnalyticsInitializer : Initializer<Unit> {
    override fun create(context: Context) {
        Analytics.init(context)
    }
    override fun dependencies() = listOf<Class<out Initializer<*>>>()
}

// В AndroidManifest.xml позначаємо як необов’язковий
// <meta-data android:name="AnalyticsInitializer"
//     android:value="false" />

Зменшення розміру DEX

Розмір DEX-файлу безпосередньо впливає на час його завантаження ART. Використовуйте R8/ProGuard для обфускації та видалення мертвого коду (MinifyEnabled = true). Увімкніть android:extractNativeLibs="false" в маніфесті, щоб APK не розпаковував .so файли при встановленні. Для проєктів з 10+ відстеженнями посилань додавайте startup-priority лише для першого екрана. Кожен зайвий метод в DEX додає 0.5–2 мс до завантаження, а для застосунків з 50k+ методів (multidex з primary dex) — до 300 мс.

Cold Start в Android Vitals

Android Vitals в Google Play Console (розділ Launch time) збирає дані з усіх пристроїв, на яких встановлено застосунок, за умови згоди користувача на анонімну діагностику. Метрики діляться на три категорії: “good” (хороший), “moderate” (середній), “bad” (поганий), залежно від часу Cold Start.

Порогові значення Google

Google визначає “bad” Cold Start як час, що перевищує 5 секунд на будь-якому пристрої. Однак на практиці для флагманських пристроїв (Snapdragon 8 Gen) хорошим вважається час менше 1.5 секунд, для середнього сегмента — менше 2.5 секунд, для бюджетного — менше 4 секунд. Android Vitals показує медіану по кожному device model, що дозволяє зрозуміти, на яких пристроях застосунок запускається повільно. Якщо Cold Start поганий на пристроях Samsung A-series або Xiaomi Redmi, причина найчастіше — слабка flash-пам’ять і малий обсяг ОЗП (прискорення через Baseline Profiles дає найбільший ефект саме на таких пристроях).

Як Google Play використовує метрику

Окрім відображення в консолі, метрика Cold Start впливає на оцінку якості застосунку в Google Play Search. Застосунки з високим відсотком “bad” запусків отримують позначку “Performance warning” на сторінці встановлення, що знижує конверсію. За даними Google (Android Performance Playbook, 2024), застосунки, що усунули Cold Start-проблеми, в середньому збільшують конверсію встановлення на 5% і покращують показник retention (D1) на 3–7%.

Інтеграція з Firebase Performance

Для більш детального моніторингу використовуйте Firebase Performance Monitoring. Він відстежує Cold Start на рівні сесій, розбиває по версіях застосунку та версіях Android. На відміну від Android Vitals, Firebase показує trace-діаграму витраченого часу по фазах. Наприклад, можна побачити, що на версії 3.2.0 Application.onCreate став займати 800 мс (через нову бібліотеку push-сповіщень), а на версії 3.2.1 — 200 мс (після виправлення).

Приклади коду для оптимізації

Нижче наведено два практичні приклади, які безпосередньо прискорюють Cold Start: перенесення ініціалізації SDK після старту та використання SplashScreen API.

Перенесення ініціалізації з Application.onCreate

Типова помилка — ініціалізація всіх SDK в Application.onCreate. Нижче показано, як перенести некритичну ініціалізацію в корутину, яка запускається після відображення першого кадру. Важливо: Firebase, Crashlytics та Crash Reporting SDK мають бути ініціалізовані на старті — їх відкладати не можна, оскільки вони ловлять краші при ініціалізації інших компонентів. Для решти використовуйте lifecycleScope при першій Activity.

kotlin
// ❌ Погано — вся ініціалізація в Application.onCreate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Firebase.init(this) // критично
        Analytics.init(this) // можна пізніше
        Database.init(this) // можна пізніше
        ImageLoader.init(this) // можна пізніше
    }
}

// ✅ Добре — Firebase на старті, решта after inflate
class App : Application() {
    override fun onCreate() {
        super.onCreate()
        Firebase.init(this)
    }
}

// В MainActivity після першого кадру:
lifecycleScope.launchWhenResumed {
    initializeNonCriticalSdks()
}

SplashScreen API

На Android 12+ використовуйте офіційний SplashScreen API, який показує system-сплеш (іконка застосунку на темному/світлому фоні) одразу при старті процесу. Це приховує час ініціалізації від користувача — він бачить сплеш, а не білий екран. Для старих пристроїв використовуйте theme-based splash (Theme.SplashScreen в стилях). Важливо: сплеш не повинен тривати довше 300 мс — якщо за цей час застосунок не готовий, намалюйте “постійний” скелетон (shimmer) і показуйте прогрес завантаження.

kotlin
// SplashScreen API — Android 12+
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        val splashScreen = installSplashScreen()
        splashScreen.setKeepOnScreenCondition {
            isReady.value == false
        }
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

// Theme-based splash (Android 5-11)
// В themes.xml:
// <style name="Theme.App.Starting" parent="Theme.SplashScreen">
//   <item name="windowSplashScreenBackground">@color/white</item>
//   <item name="windowSplashScreenAnimatedIcon">@mipmap/ic_launcher</item>
// </style>

Часті запитання

Чому Cold Start на емуляторі швидше, ніж на пристрої?

Емулятор використовує потужний хост-комп’ютер та емулює процесор з апаратним прискоренням (HAXM / WHPX). Фізичні пристрої, особливо бюджетні (eMMC-пам’ять замість UFS), мають набагато повільніший I/O. Рекомендується вимірювати Cold Start на фізичному пристрої середнього сегмента, щоб отримати реалістичні дані.

Який Cold Start вважається прийнятним?

За рекомендаціями Google, медіанний Cold Start має бути менше 2 секунд на пристроях середнього сегмента. Для флагманів — менше 1.5 секунд. Для бюджетних пристроїв (2 ГБ ОЗП) допустимо до 4 секунд, але рекомендується оптимізувати до 3 секунд. Значення більше 5 секунд вважаються критичними.

Чи впливає розмір іконки на швидкість Cold Start?

Опосередковано — так. Якщо в маніфесті вказана vector-іконка (AdaptiveIcon), вона має бути скомпільована в drawable при старті. Якщо іконка містить складні шляхи (pathData з десятками кривих), компіляція займає 10–30 мс. Використовуйте VectorDrawable з оптимізованим pathData (через SVGOMG або Android Studio Vector Asset).

Чи потрібно оптимізувати Cold Start в Feature Module?

Так, якщо Feature Module (Android App Bundle) завантажується на вимогу (on-demand), його Cold Start вважається від моменту натискання на фічу до першого кадру. On-demand модулі завантажуються через Play Core Library, і їх встановлення додає 500–3000 мс до часу старту. Оптимізуйте код фічі так само, як і основний модуль.

Як Multidex впливає на Cold Start?

Застосунки з більш ніж 64k методів потребують Multidex. Це означає, що ART має завантажити кілька DEX-файлів, що збільшує час Cold Start на 200–800 мс залежно від кількості classes.dex. Використовуйте minSdk 21+ (ART з підтримкою native multidex) та налаштуйте primary dex через --main-dex-list, щоб критичні класи були в першому DEX-файлі.

Підсумки

  • Cold Start — повний запуск застосунку зі створенням нового процесу, часом 1–5 секунд
  • Вимірюється через ADB shell am start -S -W або Macrobenchmark в CI/CD
  • Чотири фази: fork → Application.onCreate → Activity.onCreate → перший кадр
  • Оптимізація: лінива ініціалізація, Baseline Profiles, App Startup Library, R8-стиснення
  • Google Play оцінює Cold Start як “bad” при часі більше 5 секунд на будь-якому пристрої
  • SplashScreen API на Android 12+ приховує час ініціалізації за system-сплешем
  • Кожні 100 мс затримки знижують утримання користувача на 3%

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також