ビットマップは、アプリで最もメモリを消費するオブジェクトであることがよくあります。デコードとスケーリングのオペレーションは、フレーム レンダリングのクリティカル パス上で行われることがよくあります。 ビットマップのメモリ使用量を最適化すると、ジャンク、ANR、OOM 関連のプロセスの強制終了が減り、UI の応答性、バッテリー寿命、全体的な安定性が大幅に向上します。
ビットマップのメモリ使用量が多いことを特定する
Android Vitals は、Android デバイスからデータを集計して、アプリのビットマップのメモリ使用量に関する指標を提供します。これらの指標には、パッケージとプロセスごとの期間ベース(28 日間など)のパーセンタイルが含まれます。このデータは、さまざまなデバイスタイプとバージョンにおけるメモリ効率の傾向と潜在的な回帰を特定するのに役立ちます。
Android Vitals は、アプリのビットマップのメモリ使用量を次の プロセス状態別に分類して共有します。
- フォアグラウンド: アプリのプロセスが表示されています。P99 は、他のプロセス状態と比較してフォアグラウンドで大幅に高くなることが想定されますが、P99/P50 比が有意な場合(3.5 倍を超える場合など)は、ビットマップのメモリリークを示していることが多いため、デベロッパーは調査する必要があります。これは、一般的な使用量(P50)と外れ値の使用量(P99)の間に差異があるかどうかを確認することで特定できます。一般的なアセットの肥大化は、すべてのパーセンタイルでメモリを均一に増加させますが、メモリリークは時間の経過とともに複合化され、末尾のデータ(P99)が大きく偏ります。アプリが他の状態に移行した後、フォアグラウンドのビットマップ割り当てが不必要に保持されないようにしてください。
- ユーザーが認識できるサービス: アプリのプロセスが 認識可能な状態で実行されています。これには、フォアグラウンド サービス、緊急 ジョブ、ユーザーが開始したデータ転送ジョブが含まれます。アプリは、これらの状態に移行する際に、大量のフォアグラウンド ビットマップ割り当てを保持してはなりません。これらのサービスは長時間実行されるタスク向けに設計されているため、大きなアセットを保持すると、全体的なユーザー エクスペリエンスが低下し、Low Memory Killer Daemon(LMKD)が優先度の低いプロセスを終了してメモリを回収することになります。
- バックグラウンド: アプリがバックグラウンド サービスを実行しているか、最近 バックグラウンドに移行したものの、まだキャッシュに保存されていません。このプロセス状態は、フォアグラウンド プロセスや認識可能なプロセスよりも重要度が低いため、アプリはここで大きなビットマップ アセットを明示的に解放して、メモリ負荷を軽減する必要があります。
- キャッシュに保存: アプリがキャッシュに保存された状態です。この状態は、LMK などのシステム メモリ負荷に非常に敏感です。アプリは、この状態でビットマップのメモリ使用量を積極的に削減して、OS による強制終了を回避する必要があります。
ビットマップのメモリ使用量が多い原因
使用されなかった仮想メモリも計算に含まれる場合があります。ビットマップのメモリ使用量が想定外に多い場合は、未使用のメモリを割り当てていないことを確認してください。
リソース
Android Studio でビットマップを分析する
ビットマップの Android Studio プロファイリング
Memory Profiler を使用して、メモリ割り当てをリアルタイムで検査し、ヒープダンプをキャプチャして、オブジェクトのメモリリークを分析します。また、ヒープ アナライザを使用して、メモリリークの検出、重複するビットマップ割り当ての特定、オブジェクトの保持の可視化を行います。
LeakCanary による自動リーク検出
LeakCanary ライブラリを統合して、アプリのメモリリークの検出を自動化します。LeakCanary は、自動ヒープ分析を提供し、破棄されたアクティビティやフラグメントによって保持されているビットマップなど、ガベージ コレクションされるべきだがメモリに保持されているオブジェクトを特定します。
ビットマップのパフォーマンスに関するドキュメント
これらのリソースでは、さまざまな Android コンポーネントでビットマップを効率的に処理するためのベスト プラクティスに関する包括的なガイダンスを提供しています。
ビットマップのメモリ使用量を最適化するためのデベロッパー向けチェックリスト
ビットマップのメモリ効率を最適化するには、削減、再利用、リサイクルの 3 つの基本原則に従います。
- 削減: ビットマップの読み込み時または表示時の初期メモリ使用量を最小限に抑えます。
- 再利用: キャッシュ メカニズムを実装して、冗長なビットマップ 割り当てを回避します。
- リサイクル: リソースを積極的に解放して、 アクティブなプロセスにメモリを再割り当てできるようにします。
次のデベロッパー向けチェックリストは、ビットマップのメモリ使用量を最適化するのに役立ちます。
| 基本原則 | 地域 | 説明 |
|---|---|---|
| 削減 | 重複するビットマップを削除する | Memory Profiler を使用してヒープダンプを分析し、冗長なビットマップ割り当てを検出します。ビットマップ メモリの管理ガイドを参照してください。 |
| 画像読み込みライブラリを活用する | Glide や Coil などのライブラリを使用して、スレッド処理、キャッシュ、効率的なデコードを自動化します。 | |
| ダウンサンプリングを実装する | 画像をデコードして、フル解像度のアセットを読み込むのではなく、ターゲット UI コンテナのサイズに合わせます。 | |
| 不透明な画像に RGB_565 を使用する | 透明度のない画像で ARGB_8888 から 16 ビット構成に切り替えることで、メモリ使用量を 50% 削減します。 |
|
| VectorDrawable を優先する | アイコンや基本的なグラフィックにベクターを使用して、メモリオーバーヘッドを最小限に抑えながらシャープなスケーリングを実現します。 | |
| サーバーサイドの画像配信を最適化する | デバイスの密度と ImageView のサイズに合わせて画像を配信するようにバックエンド API を構成します。 | |
| 透明な余白を削除する | 組み込みの余白の代わりに InsetDrawable またはレイアウト パディングを使用して、「非表示」ピクセルにメモリを割り当てないようにします。メモリ効率の高い Android アプリを設計するをご覧ください。 | |
| 再利用 | 最適なキャッシュ サイズを構成する | デバイスの RAM と画面解像度に基づいて、メモリとディスク キャッシュの上限を調整します。ビットマップのキャッシュ保存を参照してください。 |
| リサイクル | バックグラウンドでリソースを削除する | TRIM_MEMORY_BACKGROUND を実装して、キャッシュをクリアし、システム メモリ負荷時のプロセス生存率を向上させます。 |
| UI が非表示になったらアセットを解放する | アプリがユーザーに表示されなくなったら、TRIM_MEMORY_UI_HIDDEN を使用してビットマップ キャッシュを解放します。 |
|
| メモリリークをモニタリングする | LeakCanary と Memory Profiler を使用して、LifecycleOwner が破棄された後に保持されているビットマップを見つけます。アプリのメモリを管理するを参照してください。 |