ローメモリ キラー

Android のローメモリ キラー(LMK)デーモンは、実行中の Android システムのメモリ状態をモニタリングしてハイメモリ プレッシャーに対応し、必要性の最も低いプロセスを停止します。Android Vitals は、ユーザーが認識した LMK 終了を Google Play Console で追跡して報告し、ユーザーに影響するメモリ プレッシャーの問題を特定できるようにします。

Android Vitals の LMK 指標

Android Vitals は、アプリの LMK 発生率をモニターして改善するために役立ちます。Android Vitals では、ユーザーが認識した LMK 発生率という 1 つの LMK 発生率のみを測定します。

この指標は、ユーザーが認識した LMK が 1 回以上発生した 1 日のアクティブ ユーザーの割合(%)を表します。ユーザーが認識した LMK とは、ユーザーが気付いた可能性が高い LMK のことです。たとえば、アプリがアクティビティを表示しているときや、フォアグラウンド サービスとして実行しているときに発生する LMK が含まれます。これらの終了により、プロセスは正常に終了せず、すぐに終了します。エンドユーザーには、アプリがクラッシュしたように見えます。多くの場合、標準のライフサイクル状態保存メカニズムがバイパスされ、ユーザーの進行状況が失われます。

Android Vitals は、メモリ管理の不適切な問題の信頼性の高いプロキシとして機能するため、これらのプロセス終了に重点を置いています。LMK 率が 1% を超えている場合は、即時の対応が不可欠であることを示しています。ただし、LMK 発生率が低いからといって、アプリのメモリ使用量が正常であるとは限りません。この割合が低いということは、LMK デーモンがバックグラウンドにあるプロセスを頻繁に強制終了していることを意味する可能性があり、その場合、「ウォーム スタート」のパフォーマンスとマルチタスクの流動性が低下します。

この指標は、Android Vitals の [安定性] セクションで確認できます。

図 1. Android Vitals でユーザーが認識した LMK 発生率を確認します。

ANR やクラッシュなどの類似の主な指標と同様に、指標をフィルタしたり、指標を同業他社と比較したり、指標の変化を長期間(最大 3 年間)モニタリングしたりできます。既存のアプリのデータは、2025 年 1 月 28 日以降のものが利用可能です。

図 2. Android Vitals の LMK 発生率の概要。

ローメモリ キラーデーモンの仕組み

Android プラットフォームは、空きメモリが無駄なメモリであるという前提で動作しています。 Android は、常に利用可能なメモリをすべて使用しようとします。たとえば、システムは、アプリが閉じられた後もメモリに保持するため、ユーザーはすぐに元のアプリに切り替えることができます。このため、Android デバイスは、ほとんどの場合、空きメモリが非常に少ない状態で動作しています(プロセス間のメモリ割り当てを参照)。

空きメモリが少なくなったときに強制終了するプロセスを決定するために、ローメモリ キラー(LMK)デーモンは、oom_adj_score と呼ばれるメモリ不足スコアを使用して、実行中のプロセスに優先順位を付けます。スコアの高いプロセスから強制終了されます。バックグラウンド アプリは最初に削除され、システム プロセスは最後に削除されます。次の表は、LMK のスコア付けカテゴリを高いものから順に示しています。1 行目の最もスコアの高いカテゴリのアイテムが最初に強制終了されます。

Android プロセス(スコアの高い順): バックグラウンド アプリ、以前使用したアプリ、ホームアプリ、サービス、認識可能なアプリ、フォアグラウンド アプリ、永続、システム、ネイティブ。
図 3. Android プロセス(上がハイスコア、下が低スコア)。

メモリ プロファイリング ツール

次のツールを使用すると、以下の方法でメモリの問題を特定して診断できます。

  • アプリによるメモリの割り当て方法を長期的に監視します。アプリのメモリ使用量、割り当てられている Java オブジェクトの数、ガベージ コレクションの実行タイミングがリアルタイムでグラフに表示されます。
  • ガベージ コレクション イベントを開始して、アプリの実行中に Java ヒープのスナップショットを取得します。
  • アプリのメモリ割り当てを記録し、割り当てられたオブジェクトをすべて検査して各割り当てのスタック トレースを表示します。

ゲームがネイティブ エンジンで実行されている場合は、HWAddressSanitizer を使用してネイティブ メモリ割り当てをデバッグします。

Android Studio Memory Profiler

Android Studio には、Android Profiler のコンポーネントとして Memory Profiler が用意されています。これは、スタッタリング、フリーズ、さらにはアプリのクラッシュを引き起こす可能性があるメモリリークとメモリチャーンを特定するために役立ちます。プロファイラには、アプリのメモリ使用量のリアルタイム グラフが表示され、ヒープダンプの取得、ガベージ コレクションの強制実行、メモリ割り当てのトラッキングを行うことができます。

ヒープ内のグローバル JNI 参照を表示する Android Studio Memory Profiler。
図 4. Android Studio Memory Profiler でグローバル JNI 参照を表示する。

Unity のメモリ プロファイリング ツール

Unity Engine を使用してアプリをビルドしている場合は、Unity メモリ プロファイリング ガイダンスに沿って操作します。Unity には、Unity でアプリケーションのメモリ使用量を分析するためのツールが 2 つ用意されています。

1 つ目は Memory Profiler モジュールです。これは、アプリケーションがメモリを使用する場所に関する基本情報を提供する組み込みプロファイラです。

メモリ モジュールには、テクスチャ メモリやメッシュメモリなどのメモリ割り当てが表示されます。
図 5. Memory モジュールが選択された Unity Profiler ウィンドウ。

2 つ目のツールは Memory Profiler パッケージです。これは、プロジェクトに追加できる Unity パッケージです。このパッケージにより、Unity エディタに Memory Profiler ウィンドウが追加されます。Memory Profiler を使用すると、アプリのメモリ使用量をさらに詳しく分析できます。スナップショットを保存して比較することで、メモリリークを検出したり、メモリ レイアウトを確認してメモリの断片化の問題を検出したりできます。

メモリ スナップショットの内訳を示す Unity Memory Profiler ウィンドウ。
図 6. Memory Profiler ウィンドウを使用してメモリ スナップショットを分析する。

Android 固有の Unity ワークフローについては、Unity ツールでメモリ使用量を確認する、Unity でメモリ使用量を最適化する、Unity ゲームの LMK をデバッグするをご覧ください。

Unreal Memory Insights

Unreal Engine で構築されたアプリは、Unreal Memory Insights を使用して、メモリ割り当てと割り当て解除に関する詳細情報(メモリブロックに関連付けられた低レベルメモリ(LLM)タグやコールスタックなど)を確認できます。

Memory Insights クエリシステムは、任意の時点でのライブ割り当ての検出、メモリ使用量の変化の特定、メモリリークの特定、短期割り当てと長期割り当ての区別を行うことができます。

UE 5.4 以降、Memory Insights は、Android プロジェクトのコールスタックを使用したメモリ トレースをサポートしています。

メインメモリのグラフ、ライブ割り当て数、割り当て / 解放イベント数を示すメモリ分析トラッカー。
図 7. Unreal の Memory Insights トラッカー。

Android 固有の Unreal ワークフローについては、Unreal でメモリ使用量を確認すると Unreal でメモリ使用量を最適化するをご覧ください。

メモリ不足の分析情報

Android には、ゲームのメモリ使用量を削減し、以前のゲーム実行が終了した理由を特定できるコールバックと API が用意されています。

コールバック

非推奨の trim コールバックを登録しないでください。Android には、システムがメモリを再利用する前にネイティブ メモリのプレッシャー イベントを検出する API が用意されておらず、きめ細かい実行メモリのトリミング コールバック(TRIM_MEMORY_RUNNING_*)は、ローメモリ キルを防止するうえで効果的ではありません。そのため、Android では TRIM_MEMORY_UI_HIDDEN と TRIM_MEMORY_BACKGROUND 以外のすべてのトリムレベルが非推奨になりました。これらの残りのコールバック(または Unity の OnApplicationPause や Unreal の ApplicationWillEnterBackgroundDelegate などのエンジン ライフサイクルに相当するもの)を使用して、ゲームがバックグラウンドに移行したときに UI と補助リソースを解放します。実装の詳細については、ゲームのメモリを削減するをご覧ください。

ゲームの終了

Android は、使用可能なすべてのメモリを使用してアプリやゲームをキャッシュに保存し、それらがすばやく読み込まれるようにします(ユーザー エクスペリエンスの向上)。ただし、メモリが制限されると、システムは最もメモリを消費するアプリやゲームを強制終了して、デバイスの通常の動作のためにメモリを解放します。

ゲームのメモリ使用量を改善するための情報、分析情報、ベスト プラクティスには、次のようなものがあります。

  • ApplicationExitInfo を使用する: この API は、前回のゲーム実行が Android システムによって強制終了された理由を返します。ApplicationExitInfo を使用して、以前のプロセス終了の理由としてメモリ不足(REASON_LOW_MEMORY)またはメモリリミッターの終了(REASON_MEMORY_LIMITER)を確認します(ゲームの ApplicationExitInfo をご覧ください)。メモリ負荷が原因でゲームが終了したかどうかを確認し、そのデバイスでメモリ使用量を減らすようにゲームを最適化できるようにします。
  • 合計物理 RAM を確認する: フォアグラウンドでゲームが強制終了されるのを防ぎ、デバイスの性能に合わせるために、デバイスごとの合計物理 RAM を確認して、それに基づいてゲームのメモリ使用量を調整します。バックグラウンドに移動した直後にアプリが強制終了されないようにする(プレーヤーがマルチタスクを行えるようにする)ことが目的の場合は、trim コールバック(具体的には TRIM_MEMORY_UI_HIDDEN)を使用して、ゲームのメモリ使用量を削減します。

参考情報