2026年1月19日 【Android/CS基礎 – メモリ管理③】ARTとGCの実装 Android セキュリティ 検索する Popular tags 生成AI(Generative AI) Vertex AI Search Looker Studio BigQuery AlloyDB Google Workspace 事例紹介 Cloud SQL Category モバイル Author はる SHARE 目次 ART (Android Runtime) とは 従来のGCの課題 現代のGCアルゴリズム(Concurrent Copying GC)について メモリリークパターン まとめ We are hiring! Content こんにちは、はるです! 今回はAndroidにおける基礎の一種であるメモリ管理についてお話ししていこうと思います。 ※ 本記事はパート2の内容を前提としています。 まだ読んでいない方は、先にパート2をご覧ください。 ⭐️ この記事で理解できること ・ARTとは ・最新のARTにおけるGCアルゴリズムについて ・メモリリークパターンとその対策 ART (Android Runtime) とは ⭐️概要 ART (Android Runtime) は、Android 5.0以降からAndroid端末に搭載されているランタイム環境です。 Android 5.0以前はDalvik VMという環境が使われていましたが、パフォーマンス向上のためARTに置き換えられました。 Dalvik VMは現在ではほとんど使われていないため、詳細は省略します。 ⭐️ARTの目的 ARTの目的は、Androidアプリのパフォーマンスと効率性を向上させることです。 具体的には以下の観点から改善を図っています: ✅パフォーマンスの向上 ・アプリの起動速度を高速化 ・実行速度の向上 ・UI操作のレスポンス改善(GC停止時間の短縮) ✅バッテリー効率の改善 ・実行時コンパイルの削減 → CPU使用率低下 ・効率的なメモリ管理 → GC頻度の削減 ✅メモリ管理の最適化 ・高度なGCアルゴリズムの導入(後述) ・メモリ断片化の解消 ・メモリ使用効率の向上 ⭐️ARTの役割 ARTはAndroidにおいて以下の役割を担っています。 ✅アプリケーションの実行基盤 ・DEXバイトコードのコンパイル(AOT/JIT) ・Java/Kotlinコードの実行 ・メモリ管理(GC、ヒープ管理) ✅HAL層を経由したハードウェア操作 これはAOSP (Android Open Source Project) と呼ばれるAndroid OSのアーキテクチャ図です。 水色のレイヤーがARTで、その上下にSystem Services層とHAL層が存在します。 HAL (Hardware Abstraction Layer) とは、ハードウェア操作を抽象化したレイヤーです。 ARTはJNI (Java Native Interface) を通じてネイティブコードを実行し、HAL層経由でハードウェアにアクセスします。 ✅System Services層との連携 System Servicesは、アプリの起動管理、通知、位置情報など、システム全体を管理する特権プロセス群です。 重要なポイント: ・System ServicesはARTの上で動作するJavaプロセス ・System ServicesもARTに依存して実行される ARTはSystem Servicesを含む、すべてのJava/Kotlinコードの実行基盤となっています。 従来のGCの課題 現代のARTでは「Concurrent Copying GC」というアルゴリズムが採用されています。 ⭐️従来のGCアルゴリズムの課題 前回、GCアルゴリズムの基本は「Mark & Sweep方式」ということを学びました。 しかし、これには様々な欠点がありました。 ❌欠点1. STW時間が長い アルゴリズム実行中、アプリはSTW(Stop The World)という状態に変化します。 これはその名の通り、アプリ自体が停止するのです。 一見、「まさかメインスレッドで処理してるのか?」と引っかかりますが実際は違います。(専用のGCスレッドで処理) 停止しないと、GC実行中にコードが実行されてさらに参照を変えられるとGC実行時点でのオブジェクトグラフと実体の依存関係の整合性が取れなくなるのです。 こうなると深刻です。 不要なのにマークされるのでメモリリークは発生するし、GC側はまだオブジェクトが存在するものとして扱ってるので何かしらの拍子にアクセスしたら実はnullでNPEクラッシュというオチがありえます。 ですから、STW状態に遷移する必要があるのです。 ただし、STW時間が長いと当然画面は止まるのでUXは最悪です。 なので、話の焦点は「どうやればSTW時間を短くできるか」に移動するというわけです。 ❌欠点2.メモリの断片化 Mark & Sweepアルゴリズムによりオブジェクトが解放されたとしましょう。 しかし、そうなると問題が出てきます。 それは利用可能メモリの断片化(フラグメンテーション)が発生することです。 このように中途半端にメモリが解放されるので、実際は使えるのにサイズが合わず利用されないメモリ領域などが発生してしまうことも問題でした。 現代のGCアルゴリズム(Concurrent Copying GC)について これらの欠点を補うために考案されたアルゴリズムが「Concurrent Copying GC」アルゴリズムです。 このアルゴリズム全体は4つのフェーズに分解され、下記のフローに沿って進行します。 ✅Phase1.初期マーク 初期マークではそれぞれのGC Rootから直接参照できるノードのみをマークします。 マークされたノードははPhase2にて走査処理の起点とされます。 ✅Phase2.並行マーク 並行マークでは、GCスレッドを使ってPhase1でマークしたノードを起点に順番に走査が走ります。 しかし、これはアプリスレッド(メインスレッド)ではないため、UXは低下しないのです。 Write Barrierも非常に重要な役割です。 マーク処理の最中に参照が変わったらオブジェクトグラフと実体が乖離して大問題となります。 これを防ぐのがWrite Barrierです。 Write Barrierは参照が書き換えられたノードに対し印を付与します。 Phase4で当該ノードは整合を保つため再走査します。 ✅Phase3.並行コピー 並行コピーでは、Phase2までの段階で到達可能と判断されたノードを新たなスペースへコピーします。 こちらもGCスレッドで行うため、UXへ影響を及ぼしません。 本作業を行う目的は空きメモリの断片化によるメモリ不足(フラグメンテーション)を防ぐためです。 簡潔に言えば、空きスペースと使用スペースをしっかり区切ってヒープ領域を最大限活用しよう、ということですね。 では、新しいスペースへコピーしたあと、アプリが古いスペースへアクセスしてデータを取ろうとした場合どうなるかというと、転送ポインタという情報を辿ってしっかり新しいスペースまで導いてくれます。 転送ポインタは、データのお引越し先を記してくれたものです。 この役割をRead Barrierと言います。 ✅Phase4.最終処理 最後ですね。 ここでは、Write / Read Barrierの精算を行います。具体的には、 Write Barrier:Phase2で印をつけたノードを新しいスペースへコピー Read Barrier:Phase3で新しいスペースに移行したにも関わらず、まだ古いスペースのポインタを参照している箇所があればそれらを新しいスペースへのポインタに書き換え。そして古いスペースは解放する。 Read Barrierの精算の際、必ずSTWが発生します。 なぜならアプリが動いていると運が悪い場合に古いスペースのポインタを参照しないようにと書き換える前に参照処理が走ってしまう可能性が考えられるからです。そうなると、解放されたポインタ(つまりアクセスしてはいけない領域)にアクセスしてしまいアプリクラッシュの発生元になります。 ここまでの流れを通して1回分のGCが完了するというわけですね。 メモリリークパターン メモリリークパターンを2つ紹介します。 本当はもっとあるのですが紹介しきれないので各自で調べてみてください。 ❌Singletonでアクティビティ保持 class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) Singleton.activity = this // リーク! } } // ❌ NGパターン object Singleton { var activity: Activity? = null } // ✅ OKパターン object Singleton { var activityRef: WeakReference? = null } 解説: Part2で説明したようにstatic領域はGC Rootになります。 そうすると、activityデータがnullにならない限り、staticのGC Rootからアクセスできてしまうからです。 つまり、到達可能フラグがONになるので回収されずリークします。 そこで、弱参照を用いることで参照元であるActivity自体が消えたら自動で回収されるようにすればリークを防げます。 ❌companion object でactivity context保持 // ❌ NGパターン class MyUtil { companion object { private var context: Context? = null fun init(context: Context) { this.context = context // ActivityのContextを渡すとリーク } } } class MyActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) MyUtil.init(this) // リーク! } } // ✅ OKパターン class MyUtil { companion object { private var appContext: Context? = null fun init(context: Context) { this.appContext = context.applicationContext // ApplicationContextを使う } } } 解説: companion object = staticなオブジェクトです。 そこに対し、Activityが生存している間しか使えないActivityContextを引き渡せば、先ほどと同じ原理でリークします。 そのため、ApplicationContextを渡すようにしましょう。 こちらは、アプリが生存している間はずっと使えるためリークに繋がりません。 まとめ いかがでしたでしょうか。 ここまで、かなり長かったですね。しかしここを押さえるとメモリリークが発生した場合の対処方法が、より理論立てて検討できるようになったのではないでしょうか? Java / Kotlinはランタイムがメモリ管理を隠蔽してくれる素晴らしい言語ですが、その内部を知ってるかどうかでメモリリークに対する意識一つとっても大きく変わるはずです。 現に、この記事を読む前と後ではみなさんのメモリ管理に対する意識も変化しているのではないでしょうか。 近年、さまざまなフレームワークやライブラリが登場しています。 一方で、プロセスやスレッド、GCなどの基礎(Fundamental)は不変です。基礎を抑えることで今後のITの変化にもついていきやすくなると思います!! We are hiring! 現在、システムサポート株式会社ではAndroid/iOSエンジニアを募集しております。 一緒にモバイルアプリチームを発展していく仲間を心よりお待ちしておりますので、何なりとお問い合わせください! キャリアサイト: コチラ doda / リクルートなどでも公開しておりますのでご確認ください。 必須要件 Swift、Kotlinいずれかを用いたモバイルアプリ開発の経験 歓迎条件 Webアプリケーション開発経験をお持ちで自己研鑽にてSwift、Kotlinを用いたモバイルアプリ開発を経験されている方 魅力 MAU200k+を誇る規模のモバイルアプリ開発なども行えるSIerとしては珍しいtoC向けアプリもあります! また、DroidKaigiやiOSDCへの参加なども積極的に推奨しているため技術力向上も狙えちゃいます! リモートワーク+フルフレックスなどWLBも充実してますので是非是非ご応募ください! 関連コンテンツ 【Android – メモリ管理①】メモリ管理の全体像を理解する by はるon 2025年12月3日 【Android – メモリ管理②】GCの仕組みについて by はるon 2025年12月4日 頂きましたご意見につきましては、今後のより良い商品開発・サービス改善に活かしていきたいと考えております。 非常に良かった とても良かった どちらでもない あまり良くなかった 非常に良くなかった Author はる 入社日:2023年12月 職種:Androidネイティブアプリエンジニア チェスが趣味 Android セキュリティ 2026年1月19日 【Android/CS基礎 – メモリ管理③】ARTとGCの実装 Category モバイル 前の記事を読む 【Looker】ガバナンスの要、LookMLこそ美しく!静的解析ツールLook at me sideways(LAMS)のすすめ【CI/CD】 Recommendation オススメ記事 2023年9月5日 Google Cloud 【Google Cloud】Looker Studio × Looker Studio Pro × Looker を徹底比較!機能・選び方を解説 2023年8月24日 Google Cloud 【Google Cloud】Migrate for Anthos and GKEでVMを移行してみた(1:概要編) 2022年10月10日 Google Cloud 【Google Cloud】AlloyDB と Cloud SQL を徹底比較してみた!!(第1回:AlloyDB の概要、性能検証編) BigQuery ML ワークショップ開催のお知らせ 生成AI導入支援パッケージ Discovery AI導入支援パッケージ Google Cloud ホワイトペーパー 新着記事 2026年1月19日 モバイル 【Android/CS基礎 – メモリ管理③】ARTとGCの実装 2026年1月16日 Google Cloud 【Looker】ガバナンスの要、LookMLこそ美しく!静的解析ツールLook at me sideways(LAMS)のすすめ【CI/CD】 2026年1月16日 モバイル 【Androidセキュリティ】fridaを用いたBypassについてめっちゃ簡単に基礎から書いてみた!! HOME モバイル 【Android/CS基礎 – メモリ管理③】ARTとGCの実装