※本記事は、Alice Yuan氏、Ajesh Pai氏、Fung Lam氏による、Google I/O 2026のセッション動画「Engineering memory-performant Android apps」の内容を基に作成されています。動画の詳細情報は https://www.youtube.com/watch?v=fOXJR5qLq54 でご覧いただけます。本記事では、動画の内容を要約しております。なお、本記事の内容は登壇者の見解を正確に反映するよう努めていますが、要約や解釈による誤りがある可能性もありますので、正確な情報や文脈については、オリジナルの動画をご視聴いただくことをお勧めいたします。
本セッションでは、コード縮小のための重要なツールであるR8や、ネイティブメモリ使用量を大幅に削減するためのビットマップ最適化のベストプラクティスについて解説しています。また、実際の利用環境においてOut of Memoryやメモリの異常を検知するための、新しいProfilingManagerトリガーの活用方法についても紹介しています。
関連リソース
- アプリの最適化を有効にする → https://goo.gle/4f4sZQl
- Keepルールの追加方法 → https://goo.gle/4nclKIh
- Keepルールのベストプラクティス → https://goo.gle/3PplkBI
- ライブラリ開発者向けの最適化 → https://goo.gle/4nhrcK2
- R8 Configuration Analyzer → https://goo.gle/4nbIEiI
- エージェントスキル → https://goo.gle/4tlJvPA
- ProfilingManager → https://goo.gle/3Rfh6NR
- ProfilingManagerトリガー → https://goo.gle/4nKAsXa
- Androidにおけるメモリ最適化の概要 → https://goo.gle/3PBe2ec
- メモリ管理の概要 → https://goo.gle/4nIe0xG
- Android 17のアプリメモリ制限 → https://goo.gle/43jvveu
登壇者 Alice Yuan氏、Ajesh Pai氏、Fung Lam氏
Google I/O 2026のAndroidセッション一覧はこちら → https://goo.gle/Android-at-IO2026 Android Developersのチャンネル登録はこちら → https://goo.gle/AndroidDevs
1. はじめに:メモリはパフォーマンスの土台である(Alice Yuan)
1.1 メモリ枯渇が引き起こすパフォーマンス問題
Alice Yuan: こんにちは、Aliceです。今日は同僚たちと一緒に、パフォーマンスの高いアプリケーションをどのようにエンジニアリングしていくかについてお話しします。私たちがパフォーマンスという言葉を使うとき、多くの方はスムーズなUIや高速な起動時間といった、目に見える指標を思い浮かべるのではないでしょうか。しかし、メモリはそうした指標を支える、いわば見えない土台なのです。もしメモリ使用量が最適化されていなければ、アプリのパフォーマンスだけでなく、ユーザー体験そのものにも悪影響が及んでしまいます。
Alice Yuan: ここで、端末の物理メモリ容量を、有限のグリッドに見立てて考えてみたいと思います。これは、デバイス上でのメモリページ使用状況を単純化して示したものです。画面表示、高解像度動画のバッファリング、あるいはオンデバイスのAIモデルなど、あらゆる処理がこのグリッドの一部を占有していきます。空いているページがある限りは、すべてがスムーズに動作します。しかし、すべてのメモリページが使い尽くされ、空きページがなくなってしまったらどうなるでしょうか。その裏側では、システムがより多くの空間を確保しようと必死にやりくりを始めます。
Alice Yuan: そして、このやりくりこそが、UIのジャンクやバッテリー消耗、ANR、さらには突然のアプリ強制終了といった、コストの大きいパフォーマンス上の問題を引き起こす原因になります。たとえば、もう使われていないオブジェクトをスキャンするために、ガベージコレクションが頻繁に発生することがあります。これが頻発すると、UIに目に見えるカクつきが生じてしまいます。また、空きメモリが一定の閾値を下回ると、カーネルのプロセスがメモリページの回収と圧縮に乗り出します。
Alice Yuan: この回収処理はCPUに大きな処理負荷をかけるため、予測不能なアプリのANRや、深刻なバッテリー消耗を引き起こすことがあります。さらに空きメモリが危機的なレベルまで低下すると、Low Memory Killerが介入し、厳格な優先順位に基づいてプロセスを丸ごと終了させ始めます。これこそが、コールドスタートの主な原因であり、ユーザーはアプリの状態がすべて再構築されるまで、長い読み込み画面を目にすることになってしまいます。また、これはより深刻な混乱も引き起こします。たとえば、バックグラウンドで再生中の音楽プレイヤーが、OSが他に終了させられるバックグラウンドプロセスを使い果たしたために、突然シャットダウンされてしまうといったケースです。メモリ消費量を最適化していないと、ANRやクラッシュに関する「不良挙動の閾値」を超えてしまうこともあり、これはGoogle Playにおけるアプリの検出性にも影響を及ぼしかねません。
Alice Yuan: そして最後に付け加えておきたいのは、Android自体も、エコシステム全体でより強固なメモリ管理とデバイスの安定性を確保するために、システムレベルでの最適化手法を新たに開発し続けているということです。
1.2 本セッションの構成
Alice Yuan: 本セッションでは、私と同僚たちから、デベロッパーの皆さんがメモリを最適化するための3つの解決策をご紹介し、最終的にアプリのユーザー体験を向上させる方法をお伝えしていきます。
Ajesh Pai: 私からは、R8ツールをどのように設定するのが最適かについてお話しします。そのあと、Fungがメモリ使用量を無駄なく保つためのベストプラクティスについて説明します。
Alice Yuan: そして最後に私から、フィールドでメモリの問題を検知できるようにするための可観測性ツールについてお話しします。このトークが終わる頃には、皆さんのアプリが今後もパフォーマンスを維持し続けるための、プロアクティブなロードマップを手にしていただけるはずです。
2. R8オプティマイザによるメモリ最適化(Ajesh Pai)
2.1 R8の効果と有効化方法
Ajesh Pai: ここからは、アプリのパフォーマンスを改善するために皆さんが取れる、最もインパクトの大きい変更の一つ、R8オプティマイザの有効化についてお話しします。R8はAPKサイズを縮小するツールとして広く知られていますが、実はメモリ使用量の削減にも大きく貢献します。APKからRAMに読み込まれるコード量が少なくなれば、アプリの消費メモリも減少するからです。R8は未使用のコードやリソースをアプリから取り除き、アプリの読み込みに必要なメモリを削減してくれます。これがなぜ重要かと言いますと、最適化されていないヒープメモリの使用は、ガベージコレクションを頻発させ、結果としてUIのジャンクを引き起こしてしまうからです。
Ajesh Pai: さらにR8は、クラスやメソッド、フィールドをより短い名前に難読化することで、メモリ使用量を削減します。これは、スタックメモリの問題が複雑で非効率なランタイムの一因となるため、重要な意味を持ちます。加えてR8は、メソッド呼び出しを実際のコードに置き換えるメソッドインライン化や、複数のクラスをマージするといった最適化を行い、ヒープサイズとスタックメモリの両方を削減します。これらの最適化がユーザーにとって何を意味するかと言えば、起動時間の高速化、レンダリングの改善、そしてANRの減少です。
Ajesh Pai: それでは、実際にコードベースでR8を有効にする方法を見ていきましょう。アプリのbuild.gradleファイルで、isShrinkResourcesをtrueに設定します。これによって、R8が未使用のリソースとコードを削除できるようになります。isMinifyEnabledをtrueに設定すると、R8がコードを最適化し、未使用のクラスを削除し、クラス名を短縮してコードサイズを縮小できるようになります。そして最後に、最適化ルールを含むデフォルトのProGuardファイルを定義します。ここで重要なのは、正しいデフォルトProGuardファイルを使用することです。レガシーファイルを使ってしまうと、R8による最適化の適用が妨げられてしまいます。なお、Android Gradle Plugin 9以降では、レガシーファイルであるproguard-android.txtはサポートされなくなりましたので、Platform Toolsに同梱されているproguard-android-optimize.txtに置き換える必要があります。一見小さな設定変更に思えるかもしれませんが、これは複数のパフォーマンス指標に大きな改善をもたらします。もしGradleプロパティファイルにR8のフルモードを無効化するフラグが含まれている場合は、そのフラグを削除して、R8の力を最大限に引き出してください。ただし、この変更は強力な最適化を有効にするものですので、変更後はアプリを十分にテストするようにしてください。
Ajesh Pai: これらの変更が実際にどれほどのインパクトを持つか、Monzoの事例をご紹介したいと思います。Monzoは1,500万人の顧客を抱え、今なお成長を続けている英国のデジタルバンクです。アプリの規模が拡大する中で、Monzoのエンジニアリングチームはアプリの起動時間を改善すべき重要な領域として特定していましたが、そのためにはコードベースに大幅な変更が必要になるのではないかと懸念していました。彼らが求めていたのは、全面的な書き直しという負担を伴わずに、パフォーマンスを向上させる方法でした。そこでR8の最適化を全面的に有効化したところ、Monzoはアプリの応答なし率、つまりANR率を35%も削減することに成功しました。さらに、遅いコールドスタートの発生率についても30%の改善が見られ、アプリ全体のサイズも9%削減できたということです。まとめますと、R8を使う際にはshrinkResourcesを有効化し、正しいデフォルトのProGuardファイルを指定し、フルモードで運用することが、最大限の最適化効果を得るためのポイントになります。
2.2 Keepルール設計のベストプラクティス
Ajesh Pai: R8がアプリを最適化する際、リフレクションを利用しているコードのように、間接的に使用されているコードまで削除してしまうことがあります。これが原因でアプリがクラッシュしてしまうケースもあります。こうした事態に対処するために使うのが、Keepルールです。Keepルールとは、リフレクションに依存しているコード部分をR8が最適化してしまわないようにするための指示です。追加する際には、新しいファイルを作成し、ProGuardファイルのDSLの中でそれを参照するようにします。Keepルールは私たちの設定の中核をなすものですので、ここでいくつかのベストプラクティスについてお話ししたいと思います。まず最も重要なのは、いかなるグローバルオプションも使用しないということです。これらはアプリ全体にわたる最適化を制限してしまうからです。
Ajesh Pai: 避けるべきグローバルなKeepルールの一つがdontoptimizeです。これはアプリ全体の最適化を無効にしてしまい、結果として著しく大きく、遅いアプリになってしまいます。dontshrinkは未使用のコードやリソースの削除を妨げ、ユーザーに肥大化したアプリのダウンロードを強いることになります。dontobfuscateは、人間にとって読みやすいクラス名やメソッド名、フィールド名を短縮名にリネームすることを妨げ、特に大規模なアプリにおいてR8によるメモリ削減効果を阻害してしまいます。もう一つよくある落とし穴が、ワイルドカードを使った広範なパッケージ全体を対象とするKeepルールです。このようなルールを書いてしまうと、そのパッケージ内のすべてのクラス、フィールド、メソッドが丸ごと保持されてしまいます。R8はそのパッケージ内の未使用クラスやメソッドを削除できず、内部ロジックの最適化もできず、名前の難読化も一切行えなくなってしまいます。こうした広範で幅広いKeepルールを持つことは、パフォーマンスの低いアプリにつながりかねませんので、削除を検討すべきです。また、AGPとR8は連携して、最適化後も保持すべきフラグメントやビュー、アクティビティを自動的に識別してくれますので、こうしたAndroidコンポーネントに対してKeepルールを書く必要はありません。整理しますと、追加すべきKeepルールは、リフレクションに依存するコードの最適化をR8が行わないようにするものだけに限るべきであり、ルールは狭い範囲に限定し、グローバルオプションや広範なパッケージ全体のルール、Androidコンポーネントに対するKeepルールは含めるべきではありません。
Ajesh Pai: もし皆さんがライブラリ開発者であれば、Keepルールを定義する場所は二箇所あります。consumer rulesファイルとinternal rulesファイルです。ライブラリを使用するアプリ側に提供する必要があるルールは、consumer rulesファイルに記述しなければなりません。これらのルールは、そのライブラリを含むすべてのアプリに自動的に組み込まれ適用されるため、リフレクションなどの間接的な手段でアクセスされるコードが確実に保持されるようになります。consumerファイルの中にdontshrinkやdontoptimize、dontobfuscateといったルールを加えてしまうことは、致命的な誤りです。なぜなら、これらのルールはアプリ側の設定にマージされてしまうため、そのライブラリを利用するすべてのアプリに対して、R8の最適化を完全に無効化させることを強制してしまうからです。このような事態を防ぐために、AGP9からは、こうしたグローバルなKeepルールをコードに含むライブラリは公開できないようになりました。一方、proguard-rules.proファイルには、そのライブラリ自身に適用されるKeepルールを記述します。このファイルはライブラリを利用するアプリ側には渡されず、ライブラリ自身のビルドプロセスの中で、ライブラリの公開APIの実装がR8によって削除されてしまわないよう保護するために使われます。ライブラリ開発者向けのKeepルールの書き方について、さらに詳しく知りたい方は、更新されたガイドをご覧いただければと思います。
2.3 R8 Configuration Analyzerとエージェントスキル
Ajesh Pai: 皆さんがR8の最適化を最大限に引き出し、的確なKeepルールを書けるようにするために、私たちは新しいバージョンのR8とともに、R8 Configuration Analyzerを導入しました。これは、R8を有効にしたビルドを実行することで生成できます。R8 Configuration Analyzerは、アプリのコードのうちどの部分が最適化の対象になっているかを可視化してくれるツールで、3つの指標を提供します。難読化スコアは、メモリを節約するためにどれだけのコードがリネームされているかを示すものです。最適化スコアは、コードのうち何パーセントが最適化されているかを示します。そして縮小スコアは、どれだけのリソースが削除されたかを示します。これら3つの指標を確認することで、アプリの設定を監視し、検証し、改善していくことができます。
Ajesh Pai: Configuration Analyzerを使うと、各Keepルールによって影響を受けているクラス、メソッド、フィールドの数を確認することができます。また、単一のKeepルールが原因で最適化されていないアプリの割合も確認できます。Keepルールごとの詳細ページには、そのルールによって最適化が妨げられているクラス、メソッド、フィールドに関する情報が表示されます。もしあるKeepルールが、本来最適化できるはずの多数のクラスやメソッド、フィールドの最適化を妨げていることが分かった場合は、それをより具体的で狭い範囲のKeepルールに置き換えることをお勧めします。さらにConfiguration Analyzerでは、どのKeepルールが他のルールを包摂しているか、つまり、より広範なKeepルールが、同じコードを既にカバーしていることによって、より狭いKeepルールを冗長にしてしまっているケースも確認できます。より多くのクラスの最適化を妨げている包摂的なKeepルールを削除することで、R8から最大限の恩恵を得られるようにしてください。なお、AndroidXやKotlinのライブラリ、その他多くの標準的なオープンソースライブラリは、既にかなり最適化されており、特定のアノテーションを含んでいますので、こうしたライブラリを包摂してしまっているKeepルールは削除することをお勧めします。また、Configuration Analyzerでは、どのライブラリが広範なKeepルールを持ち込んでいるかも確認できますので、該当するライブラリの開発者に問題を報告するか、同じ目的を果たす、より最適化された代替ライブラリの利用を検討するとよいでしょう。まとめますと、R8はパフォーマンスの高いAndroidアプリを構築するための基盤となるツールです。R8による最適化は、より小さく、よりパフォーマンスの高いアプリへの第一歩です。その効果を最大化するためには、正しい設定でR8を有効化し、最大限の最適化を引き出すKeepルールを定義し、R8 Configuration Analyzerによって設定を検証し改善していくことが求められます。
Ajesh Pai: さらに開発プロセスをスピードアップするために、私たちはAndroid Studio AgentやほかのAIツールと組み合わせて使えるエージェントスキルを追加しました。この新しいエージェントスキルは、既存のR8設定を整理し、設定ミスを解消することで、皆さんのセットアップを効率化してくれます。そのうえで、Configuration Analyzerを活用してKeepルールがコードベースにどのような影響を与えているかを明らかにし、最終的にそれらのルールを最適化するための具体的なアドバイスを提示してくれます。このエージェントスキルによって、最小限の労力でアプリのパフォーマンスを改善できるようになります。エージェントスキルの詳細や使い方については、こちらでご案内していますので、ぜひご覧ください。次は、Fungからさらなるメモリ最適化の方法についてお話しします。
3. ビットマップとメモリのベストプラクティス(Fung Lam)
3.1 ビットマップ最適化の4つの実践
Fung Lam: メモリ使用量を最適化するために皆さんができる、最もインパクトの大きいことの一つについてお話ししたいと思います。それはビットマップです。今日のマルチメディア全盛の世界では、ユーザーはソーシャルメディアの閲覧や写真の共有、レストラン探しなど、スマートフォンの画面上で多くの時間を画像とともに過ごしています。ビットマップ画像はあらゆるところに存在しており、だからこそ皆さんが注力すべき対象なのです。ビットマップは、アプリが扱うことになる、最も一般的でありながら最大のメモリオブジェクトです。ビットマップのデコード処理をはじめ、ビットマップの寸法に応じて処理量が変化するさまざまな操作は、しばしばフレーム描画のクリティカルパス上に位置しています。そして、ディスプレイが大型化・高密度化するのに伴って、ビットマップのサイズも増大し続けています。ですので、メモリ改善のためにまず検討すべきなのがビットマップの最適化なのです。今日は、皆さんが今すぐ取り入れられる4つのベストプラクティスをご紹介します。
Fung Lam: 一つ目はスケーリングです。4Kの画像を、小さなサムネイル用の画像ビューにそのまま読み込むようなことは、決してしないでください。そうしてしまうと、ユーザーには見えないほどの細部のために、膨大な量のRAMを消費することになってしまいます。BitmapFactory.Optionsの中でinSampleSizeを使って縮小版を読み込むか、あるいはこの処理を自動的に行ってくれるGlideやCoilのようなライブラリを利用するとよいでしょう。二つ目はクロッピングです。レターボックスやフレーミングのためにビットマップにパディングを追加する必要はありません。そうした処理は、はるかに多くのメモリを消費してしまいます。三つ目はConfigです。デフォルトの設定であるARGB_8888は、RGB_565に比べて2倍のメモリを消費します。もしサムネイルを読み込んでいて透明度が不要なのであれば、RGB_565を使用してください。それ以外のケースにおいても、RGB_565で十分な画質が得られるかどうかを検討する価値はあります。そして最後に、Bitmap Poolの活用です。これによってビットマップの数やメモリ割り当ての回数を削減できます。この点についても、GlideやCoilといったライブラリの活用が助けになります。
3.2 重複ビットマップ検出とメモリリーク対策
Fung Lam: 再利用という話が出ましたが、Android Studioが重複したビットマップの使用を見つける手助けをしてくれることをご存知でしょうか。Android Studioでは、Profilerペインの中でAnalyze Memory Usageを選択し、プロファイリングを開始することで、アプリをプロファイリングすることができます。数秒待つと、ヒープダンプの詳細が表示されます。黄色い三角形のマークが見えるでしょうか。そう、これによって重複したビットマップがハイライト表示されるのです。とはいえ、どれが重複したビットマップなのか、どうやって分かればよいのでしょうか。ご心配なく。詳細部分をクリックすれば、画像のプレビューが表示され、どこでこの重複が発生しているのかをより具体的に把握できるようになっています。
Fung Lam: ビットマップの使用を最適化した後、次に取り組むべきステップは何でしょうか。それはメモリリークです。メモリリークを軽視してはいけません。これらは時間の経過とともに蓄積し、膨大な量のメモリを消費してしまいます。そしてこの点についても、Android Studioの中に皆さんの助けとなる機能が用意されています。Android Studioでは、LeakCanaryを使って、手間をかけることなくメモリリークを見つけられるようになりました。リーク解析はIDEの中に統合されており、皆さんのソースコードとも連携しているため、ソースへのジャンプ機能をはじめとした、さまざまな便利な連携機能が提供されています。また、リーク解析の結果をまるごとコピーして、Geminiでさらなる分析を行うこともできます。これによって、メモリリークの調査や修正にかかる手間と時間を削減できる可能性があります。ここで簡単に振り返っておきますと、ビットマップはアプリにおいて最も一般的な大きなメモリオブジェクトです。ビットマップの使用を最適化することで、大幅なメモリ改善をもたらすことができます。そして、Android Studioは重複したビットマップの発見やメモリリークの修正を助けてくれます。ここからは、より高度なメモリプロファイリングツールについて、Aliceからご紹介します。
4. 高度なメモリ可観測性ツール:Profiling Manager(Alice Yuan)
4.1 Profiling Manager APIの概要とイベントトリガー
Alice Yuan: ここまで、基礎的なメモリのベストプラクティスとツールについて学んできましたので、次は皆さんのメモリデバッグと分析をさらに一段階引き上げるための、高度なツールについてお話ししたいと思います。Profiling Managerは、Android 15で導入された高度なパフォーマンス可観測性APIです。これは、実際のユーザー端末からPerfettoプロファイルをプログラム的に収集できる唯一のAPIです。
Alice Yuan: Profiling Manager APIは、2種類のプロファイル収集方式をサポートしています。一つはアプリ主導型プロファイルで、この方式では開発者が収集プロセスの開始と終了を明示的に定義する必要があります。今回のセッションでは、システムによって自動的に収集されるイベント駆動型プロファイルに焦点を当ててお話しします。Profiling Managerのローンチ以降、私たちはイベントベースのパフォーマンストリガーの数を大幅に拡充してきました。Android 16で導入されたANRやapp_fully_drawn、force_stopといったトリガーに加えて、Android 17では新たに4つのイベントトリガーをローンチします。コールドスタート、過剰なCPU使用によるkill、Out of Memory、そしてAnomalyです。本日は、この中でもメモリに関連する2つのトリガー、Out of MemoryとAnomalyに焦点を当ててご紹介します。
Alice Yuan: Anomalyトリガーは、システムによって検知されたパフォーマンス上の異常を識別するものです。現在サポートされているのは、メモリとバイナリスパムという2種類の異常です。メモリ使用量がシステムの定める違反とみなされる閾値を超えると、ヒープダンプがトリガーされます。これにより、Anomalyトリガーを使って、リソースの割り当て状況やアプリケーションの状態を調べ、問題の根本原因を特定することができるようになります。Android 17で導入されるメモリ制限の強制適用をサポートするために、Anomalyトリガーはアプリが終了させられる前の段階で、ヒープダンプを提供する仕組みになっています。一方、Out of Memoryトリガーでは、Profiling Managerがメモリ不足エラーの発生を監視しています。エラーが発生すると、システムは自動的にJavaヒープダンプを収集します。これによって、クラッシュが発生した瞬間のヒープオブジェクトの割り当て状況が正確に記録され、標準的なスタックトレースよりもはるかに有用なデバッグ情報が得られるようになります。
4.2 実装手順とデータ収集の流れ
Alice Yuan: それでは、Profiling Managerのトリガーを実際にどのように作成するか見ていきましょう。ここでは例としてOut of Memoryイベントを使いますが、このロジックはほかの任意のイベントトリガーに置き換えて収集することも可能です。システムトリガーのリスニングを開始するには、以下の手順を行います。まず、AndroidXのtracingライブラリとcoreライブラリをインポートします。次に、アプリケーションの起動が完了した段階で、システムサービスからProfiling Managerを取得して初期化します。そして、デバッグしたいと考えているすべてのパフォーマンストリガーを登録します。今回のシナリオでは、Out of Memoryトリガーがそれに該当します。続いて、結果を受け取るためのコールバックリスナーを渡すことで、プロファイリング結果のリスナー登録を行います。
Alice Yuan: この結果リスナーは、プロファイルの完了をリッスンするConsumerリスナーとして定義されます。Out of Memoryのクラッシュトリガーや、アプリが強制終了させられるほかのトリガーの場合、このデータはアプリの次回起動時に返却される仕組みになっています。Out of Memoryトリガーの結果が返却されると、そのプロファイリング結果はローカルのファイルパスとして提供されます。そして、このプロファイリング結果のファイルは、手動での分析や一括分析のために、WorkManagerを使ってサーバーにアップロードすることができます。
4.3 実演:OOMクラッシュのヒープダンプ解析
Alice Yuan: それでは、Profiling Managerを使って収集したヒープダンプを実際にどのように手動で調査し、根本原因を特定していくのか、実演を交えてご紹介したいと思います。ここでは、Out of Memoryのクラッシュを受け取った、ファイル解析を行うサンプルアプリを例に、デモを進めていきます。このデータを調査するために、パフォーマンスや計測、分析結果を可視化するツールであるPerfetto UIを使用します。記録されたヒープダンプを調査する際には、UIPerfetto.devに直接アクセスし、トレースファイルをドラッグアンドドロップするか、開くことで利用できます。こちらが、私が作成したOut of Memoryクラッシュを受け取ったサンプルアプリの、ヒープダンプの見え方です。
Alice Yuan: Perfettoは、ルートとなるJavaオブジェクトとともに、メモリ割り当ての階層構造を表示してくれます。このヒープダンプにおけるルートのメモリ割り当てが、非常に大きなものであることが分かります。実際、これは端末メーカーが定めた最大ヒープサイズである256メガバイトを超えてしまっています。また、Perfettoはフレームグラフの中で、多数の小さなオブジェクトを「merged」と呼ばれる結合されたスライスへとまとめて表示してくれます。マージされた小さなオブジェクトは、通常Out of Memory障害の原因として重要ではないことが多いため、デベロッパーは一般的に、より大きなオブジェクトに絞ってデバッグ作業を進めることができます。スタックの一部をクリックし、Show Stack機能を使うことで、そのスタックを分離して確認することもできます。こうした調査の結果、最終的に私は、過剰なヒープ使用の根本原因が、MainActivity内のクラスにあるParseLargeFileにあることを突き止めました。ファイル解析の過程で生成された文字列オブジェクトへの参照を、不必要に保持し続けてしまっていたために、それらがガベージコレクションの対象から外れてしまっていたのです。この参照を解放することで、Out of Memoryの問題を解決することができました。
Alice Yuan: なお、Profiling Managerは、ネイティブメモリの使用状況をより深く把握するためのヒーププロファイルの収集もサポートしており、ビットマップのようなアロケーションを最適化する際の助けにもなります。詳しく知りたい方は、こちらのPerfettoのドキュメントをご覧ください。ここまでの内容を振り返りますと、Profiling Managerは、実際のフィールドで得られる、実用的なパフォーマンスデータを提供してくれるパフォーマンス可観測性APIです。Profiling Managerは、Out of Memoryやメモリの異常といった、Android 17におけるイベント駆動型のプロファイルを記録することができます。そして最後に、Perfetto UIを活用することで、ヒープダンプを分析し、メモリオブジェクトの割り当て状況をより深く理解することができるのです。
5. まとめ
Alice Yuan: これで、パフォーマンスの高いアプリケーションをエンジニアリングするというテーマについて、私たちからお話しすべきことはすべてです。今日ご紹介した戦略を実践していただくことで、皆さんはユーザーにスムーズな体験を届け続けるための、プロアクティブなメモリロードマップへとシフトしていくことができます。まず、狭く具体的なKeepルールでR8を設定し、バイトコードの最適化を最大限に引き出すことで、アプリサイズを小さく保ってください。
Alice Yuan: 次に、ビットマップの読み込みを最適化することで、メモリ使用量を無駄なく保ってください。また、Android StudioのLeakCanary統合機能を使えば、IDEの中で直接、早い段階からメモリリークを捕捉することができます。そして最後に、Android 17で導入されるProfiling ManagerのAPIの新しいイベント駆動型トリガーを活用してください。これによって、Out of Memoryクラッシュやメモリの異常が発生した際に、ヒープダンプを自動的に取得できるようになります。
Alice Yuan: 本日ご紹介した内容に関する追加のリソースについては、動画の概要欄にすべてまとめてありますので、ぜひご確認ください。ご視聴いただき、ありがとうございました。