Cold Startとは、アプリケーションのプロセスがメモリに存在せず、Activityが作成されていないゼロ状態から始まるAndroidアプリケーションの完全な起動サイクルです。システムは新しいプロセスを作成し、クラスをロードし、Applicationを初期化し、Activityを作成し、最初の描画を実行します。Google、2024年によると、ミッドレンジデバイスでのコールドスタートには1〜5秒かかる可能性があり、100ミリ秒の遅延ごとにユーザー維持確率が3%低下します。
重要なポイント
Cold Start(コールドスタート)は、Androidアプリケーションが最も初期の状態から起動されるシナリオです:オペレーティングシステムが新しいプロセスを作成し(Zygoteからのfork)、メモリを割り当て、DEXコードをARTにロードし、クラスを初期化し、Applicationインスタンスを作成し、次に最初のActivityを作成します。アプリ起動前には、Background Dexoptが使用されている場合のキャッシュされたクラスイメージを除き、デバイスメモリにアプリに関するデータはありません。
コールドスタートは3つのケースで発生します:アプリインストール後の初回起動時、デバイス再起動後の起動時、そしてメモリ不足によりシステムがプロセスを削除した後の起動時です。2〜4GBのRAMを搭載したデバイスでは、システムはバックグラウンドプロセスをかなり積極的に削除するため、Cold Startはユーザーが数時間の非アクティブ後にアプリに戻るたびに発生する可能性があります。Android 12+では、システムは凍結されたプロセス(freeze / cached)を保持できますが、アクティブなメモリ節約(OOM-killer)により、プロセスは終了されます。
Google(Find My Deviceレポート、2023年)によると、65%のユーザーがアプリが3秒以内に開かない場合に閉じます。ソーシャルネットワークやメッセンジャーでは、ユーザーが1日に何十回も戻ってくるため、Cold Startはリテンションに直接影響します。Google Play Consoleでは、Cold StartメトリクスはAndroid Vitalsセクションの一部であり、ANRとパフォーマンス指標の一つとして表示されます。「不良」のCold Startしきい値(25%のデバイスで5秒以上)を超えるアプリは、コンソールで警告を受け、検索結果で順位が下がる可能性があります。
Androidは3種類のアプリ起動を区別しており、それぞれ持続時間、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はコンパイルされたクラスイメージ(Boot ProfileのImage)をキャッシュし、その後のDEXロードが高速になります。したがって、最初のCold Start後の2回目の起動は通常20〜40%高速です。アプリがBaseline Profilesを使用する場合、プロファイルは最初の起動時にロードされ、2回目の起動はさらに高速になります:Baseline Profilesを公開したGoogle Playは、Android 12+搭載デバイスでCold Startを30%高速化しました。
Cold Startは厳密に定義された段階で構成され、それぞれ独立して測定および最適化できます。段階を理解することで、アプリがどの段階で時間を失っているかを特定できます。Googleは4つの主要な段階を特定しています:プロセス作成、Application初期化、Activity作成、最初のフレーム。
Androidシステム(ActivityManagerService)は、Zygoteプロセスからのforkによって新しいプロセスを作成します。Zygoteは一般的なAndroidクラスが事前にロードされたプロセスです。forkには30〜80ミリ秒かかります — この時間はアプリの制御外です。fork後、ActivityThreadが開始されます — アプリケーションのメインループインスタンスです。この段階では、ClassLoaderを介したクラスロードも発生し、ARTが最初のバイトコードの解釈を開始します。アプリが多くの静的初期化子を使用する場合、この段階は長引く可能性があります。
ActivityThreadの開始直後に、Application.onCreateが呼び出されます。ここで開発者は最も頻繁に誤りを犯し、すべてを一度に初期化します:Crashlytics、Firebase、ネットワーククライアント、データベース、Daggerコンポーネント、DIコンテナ。これらの各初期化はメインスレッドでブロックされる時間です。Application.onCreateに500ミリ秒かかる場合、ユーザーは0.5秒間、白(または黒)の画面を見ることになります。ミッドレンジデバイスでのこの段階の最適な持続時間は200ミリ秒未満です。
Applicationの初期化後、Activityインスタンスが作成されます(MainActivityまたはLauncher Activity)。Activity.onCreateが呼び出され、setContentView、フラグメントの初期化、ViewModelのセットアップ、LiveData/Flowのサブスクリプションが行われます。onCreateがメインスレッドでデータ(SharedPreferences、SQLite、API)を同期的にロードする場合、段階が延長されます。目標は、ミッドレンジデバイスでonCreateを200〜400ミリ秒に収めることです。
onCreateの完了後、最初のレンダリングが開始されます:測定、レイアウト、描画。この瞬間をTTFD(Time To First Draw)と呼びます。アプリがスプラッシュ画面(Android 12+のSplashScreen API、またはテーマ経由)を使用する場合、レンダリングはより速く行われる可能性がありますが、ユーザーはスプラッシュが消えるまで待機します。Cold Startの理想的なTTFDは1.5秒未満です。
Cold Startの測定には特別なツールが必要です。通常のロギング(Log.d)はApplication作成後にしか機能し始めず、forkのタイミングとクラスロードにはアクセスできないためです。Googleは3つの方法を推奨しています:ADBコマンド、Android Vitals、カスタムパフォーマンスマクロ。
最もシンプルで再現性のある方法は、adb shell am start -S -Wコマンドです。-Sフラグは起動前にアプリを強制的に停止します(Cold Startを保証)。コマンドは3つのメトリクスを出力します:ThisTime(Activity開始時間)、TotalTime(プロセス起動を含む合計時間)、WaitTime(Activity Managerのすべての遅延を含む時間)。クリーンな測定のために、5〜7回の測定を行い、中央値を使用してください — 単一の測定値はノイズ(CPUスロットリング、バックグラウンド負荷)の影響を受けます。
# 測定を伴う強制Cold Start
$ adb shell am start -S -W \
com.example.app/.MainActivity
# コマンド出力:
# ThisTime: 1842 ms
# TotalTime: 1842 ms
# WaitTime: 1855 ms
Google Play Consoleは、アプリがインストールされているすべてのデバイスから匿名メトリクスを収集します。Android Vitals → Launch timeセクションには、デバイスモデルとAndroidバージョン別のCold Startの中央値分布が表示されます。これは、テストデバイスだけでなく、ユーザーのデバイスでの実際のメトリクスを確認する唯一の方法です。Redmi 9A(2GB RAM)でCold Startが5秒を超え、Pixel 8で1.2秒の場合、問題はメモリサイズとクラス数です。Googleは25パーセンタイルに基づくユーザー知覚遅延も表示します。
Google Jetpack Macrobenchmark(androidx.benchmarkライブラリ)を使用すると、インストルメント化されたアプリ起動テストを作成できます。テストはアプリをインストールし、コールド状態から起動し、最初のフレームまでの時間を測定します。Macrobenchmarkは自動的に20回の実行を行い、外れ値を破棄し、安定したパーセンタイルを表示します。CI/CDでは、ベースラインと現在の起動を比較できます — 時間が増加した場合、CIパイプラインを失敗させることができます。
Cold Startの最適化は、コード、リソース、ビルド構成、初期化アーキテクチャなど、アプリの複数のレベルに影響を与える体系的な作業です。Googleは最もコストのかかる部分 — Application.onCreate — から始めて、細部に進むことを推奨しています。
起動時に必要ないすべての初期化をApplication.onCreateから最初の使用ポイントに移動します。Firebase、Crashlytics、アナリティクスSDK、プッシュ通知、DIコンポーネント — すべて最初の画面がレンダリングされた後に初期化できます。KotlinではLazy(by lazy)を、または明示的なinitialize(context)呼び出しによるContentProvider初期化を使用します。Google(Android Performance、2023年)によると、遅延初期化は5つ以上のSDKを使用するアプリのCold Startを40〜60%削減します。
Baseline Profilesは、アプリ起動時に使用される重要なクラスとメソッドのAOTコンパイルです。Baseline Profilesがない場合、ARTはDEXコードを解釈するかJITでコンパイルするため、時間がかかります。プロファイルを使用すると、ARTはアプリインストール時に指定されたメソッドをネイティブコード(AOT)にコンパイルします。Googleは、Baseline ProfilesがAndroid 9+でCold Startを15〜40%、Android 12+のART最適化で最大60%高速化すると述べています。プロファイルを作成するには、androidx.benchmark:benchmark-baseline-profile-gradle-pluginプラグインを使用します。
androidx.startupライブラリを使用すると、コンポーネントの初期化を整理し、単一のContentProviderで実行できます。異なるライブラリの複数のContentProvider(それぞれがコールドスタートに1〜2ミリ秒追加)の代わりに、App Startupはそれらを依存関係グラフにマージし、必要に応じて厳密に初期化します。起動時には、最初の画面に必要な@Initializerでマークされたコンポーネントのみが実行されます。その他にはneedEarlyInit = falseフラグが設定され、最初のレンダリング後に起動されます。
// 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ファイルのサイズは、ARTのロード時間に直接影響します。難読化とデッドコード削除にはR8/ProGuardを使用します(MinifyEnabled = true)。マニフェストでandroid:extractNativeLibs="false"を有効にすると、APKがインストール時に.soファイルを展開しなくなります。10以上の参照追跡を持つプロジェクトでは、最初の画面にのみstartup-priorityを追加します。DEXのメソッドが1つ増えるごとにロード時間が0.5〜2ミリ秒増加し、50k以上のメソッドを持つアプリ(primary dexを持つmultidex)では最大300ミリ秒になります。
Google Play ConsoleのAndroid Vitals(Launch timeセクション)は、ユーザーが匿名診断に同意した場合に、アプリがインストールされているすべてのデバイスからデータを収集します。メトリクスはCold Start時間に基づいて3つのカテゴリに分けられます:「良好」、「普通」、「不良」。
Googleは「不良」のCold Startを、任意のデバイスで5秒を超える時間と定義しています。ただし、実際には、フラッグシップデバイス(Snapdragon 8 Gen)では良好な時間は1.5秒未満、ミッドレンジでは2.5秒未満、低価格帯では4秒未満です。Android Vitalsは各デバイスモデルの中央値を表示し、どのデバイスでアプリの起動が遅いかを把握できます。Samsung A-seriesやXiaomi RedmiデバイスでCold Startが不良の場合、原因はほとんどの場合、フラッシュメモリの低速さとRAMの少なさです(Baseline Profilesによる高速化は、このようなデバイスで最も効果を発揮します)。
コンソールでの表示に加えて、Cold StartメトリクスはGoogle Play Searchでのアプリ品質評価に影響します。「不良」起動の割合が高いアプリは、インストールページに「パフォーマンス警告」ラベルが表示され、コンバージョンが低下します。Google(Android Performance Playbook、2024年)によると、Cold Startの問題を解決したアプリは、インストールコンバージョンが平均5%向上し、リテンション(D1)が3〜7%改善されました。
より詳細な監視には、Firebase Performance Monitoringを使用します。これはセッションレベルでCold Startを追跡し、アプリバージョンとAndroidバージョンごとに分類します。Android Vitalsとは異なり、Firebaseはフェーズごとの消費時間のトレース図を表示します。例えば、バージョン3.2.0ではApplication.onCreateに800ミリ秒かかった(新しいプッシュ通知ライブラリのため)が、バージョン3.2.1では200ミリ秒(修正後)であることがわかります。
以下に、Cold Startを直接高速化する2つの実践的な例を示します:起動後のSDK初期化の移動とSplashScreen APIの使用。
典型的な誤りは、すべてのSDKをApplication.onCreateで初期化することです。以下では、重要でない初期化を最初のフレーム描画後に起動するコルーチンに移動する方法を示します。重要:Firebase、Crashlytics、Crash Reporting SDKは起動時に初期化する必要があります — これらは他のコンポーネントの初期化中にクラッシュをキャッチするため、延期できません。残りについては、最初のActivityでlifecycleScopeを使用します。
// ❌ 悪い — すべての初期化を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()
}
Android 12+では、プロセス開始時にシステムスプラッシュ(暗い/明るい背景にアプリアイコン)を即座に表示する公式のSplashScreen APIを使用します。これにより、ユーザーから初期化時間が隠蔽されます — 白い画面の代わりにスプラッシュが表示されます。古いデバイスでは、theme-based splash(スタイルのTheme.SplashScreen)を使用します。重要:スプラッシュは300ミリ秒以上続くべきではありません — それまでにアプリの準備ができていない場合は、「永続的な」スケルトン(shimmer)を描画し、読み込み進捗を表示します。
// 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)
}
}
// テーマベースのスプラッシュ(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>
よくある質問
エミュレーターは強力なホストコンピューターを使用し、ハードウェアアクセラレーション(HAXM / WHPX)でプロセッサをエミュレートします。物理デバイス、特に低価格帯のもの(UFSではなくeMMCストレージ)は、I/Oがはるかに遅くなります。現実的なデータを得るには、ミッドレンジの物理デバイスでCold Startを測定することをお勧めします。
Googleの推奨によると、ミッドレンジデバイスでの中央値Cold Startは2秒未満であるべきです。フラッグシップでは1.5秒未満。低価格帯デバイス(2GB RAM)では最大4秒まで許容されますが、3秒への最適化が推奨されます。5秒を超える値は重大と見なされます。
間接的には — はい。マニフェストにベクターアイコン(AdaptiveIcon)が含まれている場合、起動時にdrawableにコンパイルする必要があります。アイコンに複雑なパス(数十の曲線を持つpathData)が含まれている場合、コンパイルに10〜30ミリ秒かかります。最適化されたpathData(SVGOMGまたはAndroid Studio Vector Asset経由)を持つVectorDrawableを使用してください。
はい、Feature Module(Android App Bundle)がオンデマンドでロードされる場合、そのCold Startは機能をタップしてから最初のフレームまで測定されます。オンデマンドモジュールはPlay Core Libraryを介してロードされ、そのインストールにより起動時間に500〜3000ミリ秒追加されます。メインモジュールと同じように機能コードを最適化してください。
64kを超えるメソッドを持つアプリにはMultidexが必要です。これはARTが複数のDEXファイルをロードする必要があることを意味し、classes.dexファイルの数に応じてCold Start時間が200〜800ミリ秒増加します。minSdk 21+(ネイティブmultidexサポート付きART)を使用し、重要なクラスを最初のDEXファイルに保持するために--main-dex-listを介してprimary dexを設定してください。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。