メモリの最適化は、Android で安定した高性能のゲーム エクスペリエンスを提供するために不可欠です。このガイドでは、メモリ効率が重要な理由、Android オペレーティング システムがプロセス メモリの制限を管理する方法、Google Play Console の新しいメモリ指標について説明します。これらの指標は、ゲームの技術的な品質をモニタリングして改善するのに役立ちます。
メモリ最適化の重要性
ゲームのメモリを最適化することは、プレーヤーの定着率を維持し、デバイスの互換性を拡大し、プラットフォームの品質基準に準拠するために不可欠です。
- コールド スタートの防止(ユーザー エクスペリエンスとユーザー維持): プレーヤーが一時的にゲームから離れる(通知に返信したり、メッセージを確認したりするなど)と、オペレーティング システムはゲームプロセスをバックグラウンドに配置します。ゲームのバックグラウンド メモリ使用量が多すぎると、システムのローメモリ キラー(LMK)は、フォアグラウンド タスク用に RAM を再利用するために、ゲーム プロセスの終了を優先します。ユーザーが次に再開するときは、シームレスで瞬時のウォーム再開ではなく、ゲームは長いコールド スタートを経なければなりません。つまり、重いグラフィック アセット、音声、ゲームエンジンのバイナリをストレージから完全に再読み込みします。バックグラウンドでのメモリ使用量を低く抑えることで、バックグラウンドでのサイレント終了を防ぎ、ユーザーの状態を維持して、プレイヤーがセッションをすぐに再開できるようにします。システム LMK の動作について詳しくは、Android Vitals - ローメモリ キラーのガイドをご覧ください。
- エコシステムとデバイスの安定性: メモリ使用量の非効率性やメモリリークは、システム全体の健全性を低下させます。システム メモリが不足すると、システムに大きな負荷がかかり、フレームレートの低下、UI のスタッター、音声のグリッチが発生します。メモリ負荷が過度に高い場合、システムの Low Memory Killer(LMK)はバックグラウンド プロセスを強制的に終了させ、他のアプリでコールド スタートが遅くなったり、タスクを切り替える際にユーザーの状態が失われたりする原因となります。
- プラットフォーム レベルの終了: Android 17(API レベル 37)以降では、メモリを過剰に使用するプロセスをシステムがより積極的に終了します。ゲームのフットプリントが高すぎると、OS は標準のスタック トレースを生成せずにプロセスを突然終了させることがあります。
- デバイスの互換性: フラッグシップ デバイスには 12 GB から 16 GB の RAM が搭載されていますが、世界のゲーム ユーザーの大部分は 4 GB または 6 GB の RAM を搭載したデバイスを使用しています。適切なメモリ管理により、複雑な個別のアセット パッケージを必要とせずに、すべてのハードウェア階層でゲームのアクセシビリティと応答性を維持できます。
Android のメモリについて
効果的なメモリ バジェット戦略を設計するには、Android プラットフォームが物理メモリを管理する方法と、ゲームのアクティブ フットプリントを測定する方法を理解する必要があります。
Android のメモリに関する基本コンセプト
プラットフォーム レベルのメモリ管理に関する基本的なコンセプトについては、公式の Memory Management Overview(メモリ管理の概要)ドキュメントをご覧ください。このリソースでは、次の 4 つのアーキテクチャ領域について説明します。
- メモリの概要: Android は、ページングとメモリ マッピング(mmap)を使用して RAM を管理します。ディスク上の従来のスワップファイルはサポートされていません。代わりに、ページ圧縮(zRAM を使用)とページ再利用によって物理メモリを解放します。
- プロセス間のメモリ割り当て: Android はシステム全体で RAM を共有します。Dalvik または ART 仮想マシンの実行に特定のヒープを割り当て、ネイティブ開発環境(C++ ゲームエンジンなど)がネイティブ システム ヒープからメモリをリクエストできるようにします。
- アプリのメモリ管理: マルチプロセス モデルで動作する Android では、アプリがライフサイクル状態を動的にモニタリングし、システム健全性をサポートするために、不要なリソース(キャッシュされていないグラフィックやビットマップなど)を自発的に解放することが求められます。
- プロセスとスレッドの概要: システムは、現在のユーザーが認識する可視性と重要度に基づいてプロセスを階層に分類し、メモリ不足の状況でどのプロセスを存続させ、どのプロセスを最初に終了させるかを決定します。
合計メモリ使用量の指標
プラットフォーム レベルの Android 17 メモリ リミッターは、合計常駐サイズ(RSS)や仮想メモリサイズではなく、合計メモリ フットプリントを使用してプロセス消費量を評価します。
メモリ フットプリントの合計 = 匿名 RSS(RssAnon)+ 圧縮されていないスワップ(VmSwap)
ゲームがプラットフォームの上限を超えないようにするには、デベロッパーがシステムレベルでこれらの指標が何を表しているかを正確に理解する必要があります。これらの指標、物理 RAM の割り当て、ファイル バックアップ ページの処理方法について詳しくは、メモリ使用量のモニタリング ガイドの RSS とスワップの指標についてをご覧ください。
メモリの制約
システムの安定性を維持し、アプリが過剰なリソースを消費しないようにするため、Android プラットフォームは実行中のプロセスのメモリ上限を管理します。
Android 17 以降のメモリ制限ツール
Android 17(API レベル 37)以上では、Linux cgroup v2 を使用してアプリごとの厳格なメモリ制限を管理し、個々のアプリがシステム全体の不安定さを引き起こすのを防ぎます。技術的な実装の詳細については、AOSP メモリ制限ガイドと メモリ効率の優先: Android 17 の重要なステップに関するブログをご覧ください。
- メカニズム: メモリ リミッターはすべてのアプリプロセスをモニタリングし、プロセスのライフサイクル状態に基づいて制限を動的に割り当てます。
- 可視プロセス(フォアグラウンド): 現在 UI を表示しているアプリのプロセスは、より大きなリソース ワーキング セットを実行することが想定されるため、より大きな上限が与えられます。
- 非表示のプロセス(バックグラウンドまたはサービス): UI を表示せずにアクティブな処理を行うアプリのプロセスは、より厳しく制限された予算に制約されます。
- カーネル属性: このサービスは、次の 2 つの主な属性に依存しています。
memory.high: ソフト上限。この値を超えると、カーネルはプロセスをスロットリングし、メモリの積極的な再利用を試みます。この再利用により、ゲームのパフォーマンスが低下する可能性があります。memory.swap.max: プロセスで使用できるスワップ領域または zRAM 領域の上限を管理します。
- 終了動作: プロセスが
memory.highを超えて匿名メモリの割り当てを続け、スワップ容量を使い果たすと、割り当てが失敗し、OS はプロセスをサイレントに強制終了します。この終了は、メモリ制限の終了理由(Android 17、26Q4 以降で利用可能)でApplicationExitInfoを使用してログに記録されます。
メモリ使用量をモニタリングする
ゲームのメモリを効果的に最適化するには、まず Android プラットフォームがフットプリントを測定する方法を理解する必要があります。Android 17 では、メモリ指標が更新され、ファイル バックアップまたは GPU プライベート メモリを除外して、匿名 RSS(RssAnon)と非圧縮スワップ(VmSwap)の合計をトラッキングします。このガイドでは、Perfetto や meminfo などのシステムレベルのツールを活用し、ProfilingManager や onTrimMemory などの診断 API を実装して、Unity と Unreal Engine 内で正確なメモリ割り当てを抽出する方法について詳しく説明します。ゲームを正確にプロファイリングし、従来のランタイム メモリ ポーリングに関連するパフォーマンスの遅延を回避する方法を理解します。
詳細については、メモリ使用量をモニタリングするをご覧ください。
メモリ削減戦略
ゲームエンジンはクロス プラットフォーム開発を簡素化しますが、デフォルトのメモリ処理によって OS レベルのメモリ上限がトリガーされることがあります。このページでは、Unity と Unreal Engine に特化した具体的な最適化手順について詳しく説明します。Java ベースの onTrimMemory に依存すると Unity でデッドロックが発生する理由と、代わりにネイティブ ライフサイクル コールバックを使用する方法について説明します。また、ASTC 8x8 テクスチャ圧縮の使用やアセット アンロードの構成など、アセット レベルの重要な最適化についても説明します。これにより、すべてのハードウェア階層でゲームをスムーズに実行できます。
詳しくは、メモリ使用量を削減するをご覧ください。