2025年12月3日

【Android – メモリ管理①】メモリ管理の全体像を理解する


Content
こんにちは、はるです!
今回はAndroidにおける基礎の一種であるメモリ管理についてお話ししていこうと思います。
昨今では新たな技術が目まぐるしく登場していますが、私はそんな時代だからこそ「基礎」や「本質」が非常に大切であると考えています。

⭐️ 本記事を読むことに必要知識
・プリミティブ型などの基礎的なプログラミング用語
・オーダ記法を用いた時間計算量の表現方法

また、本テーマは記事を3つに分解していく予定です。
・Part1(本記事):メモリ管理の全体像 - GC/kswapd/lmkの役割
・Part2:GCの仕組み - 到達可能性と参照の種類
・Part3:ARTとGCの関連性 - Android実装の詳細

まずは、主要なデータ領域から紹介していきます。
データ領域は何種類かありますがその中で特に重要なヒープについて紹介します。
メソッド領域などは割愛します。

ヒープとは?

※ヒープについて深掘りすると記事の量が増えるので浅くします

⭐️ ヒープとは?
動的にメモリを確保・解放できる領域です。
サイズや寿命(いつ破棄するか)がコンパイル時に確定していないデータ、非プリミティブなデータなどを格納します。

⭐️ ヒープの強み
・サイズが可変(リストが伸び縮みする等)
・関数を超えて生存できる
・ポインタ経由でのアクセスはO(1)

⭐️ ヒープの弱み
・メモリ管理(GC)が必要
・確保及び解放にコストがかかる

ListやClassなど、非プリミティブ型のオブジェクトは基本的にヒープに格納されます。

⭐️ ヒープまとめ
ヒープは可変データを格納できる柔軟なデータ構造で、ポインタ経由のアクセスはO(1)と高速です。
一方で、メモリ管理にコストがかかり、不要なオブジェクトを回収するためにGCが必要になります。

メモリリークとは

まず、メモリは「使ってる間だけは参照を通じて領域を確保。使わなくなったら解放して他に譲る」これがベースです。オンデマンド方式のようなものです。
これに対しメモリリークとは、「もう使わないのに何かしらの要因で参照が残ってしまっており、GCに回収及び解放されず占有している状態」を指します。

さらに話すと、マークビットなどが絡むのですがこれは別パートにてお話しします。

メモリ管理の手法の基本的な枠組み

⭐️ 全体について
基本的に下記の流れで管理していきます。
ヒープ単位の管理

ページ単位の管理

プロセス単位の管理

ヒープ単位で十分なRAMを確保できなければページ単位の管理が発動して、それさえ無理だったらプロセス単位の管理になります。
詳細を話していきます。

⭐️ ヒープ単位
まず、基本的に1アプリ毎に1プロセス付与されます。
そして、1プロセス毎に1ヒープ与えられます。(厳密には複数あるようですが)
GCはヒープ内での最適化を図るものです。
つまり、GCはヒープ単位での最適化を図る方式ですね。

ただし、メモリリークが頻発したり他アプリ(他プロセス)による圧迫を受けてGCだけでは立ちいかなくなった場合にページ単位で発動するのが次です。

⭐️ ページ単位
kswapd(カーネルスワップデーモン)が呼ばれます。
これは、RAMが不足してきたら使用頻度の低いメモリページを退避させます。
また、退避先としてzRAMという圧縮領域を使用します。
zRAMはRAMの一部を圧縮専用領域として確保したもので、ページを圧縮して格納することで実質的な容量を増やします。
軽く、圧縮方式についても言及します。
例えば、AAAAAABBCCみたいなデータがあったとしたらこれをA6B2C2みたいに規則性を利用して短縮化して全体データサイズを削減します。
実際にはLZ4などの高速な圧縮アルゴリズムが使われます。
因みに、LZ4が採用される理由について話すと、圧縮率は低いが圧縮/解凍速度が非常に高速なためです。
現代のデバイスはRAMが多いので圧縮率よりも速度重視ですから、圧縮率の低さは然程問題にはならなかったようです。

そしてこれでもRAMが確保できなかった場合、プロセス単位の処理が走ります。

⭐️ プロセス単位
lmk(LowMemoryKiller)が呼ばれます。
これが発動するとプロセスを強制終了させます。
先ほど、1アプリ=1プロセスという話をしましたがつまりlmkが発動するとアプリが強制終了されるのです。
どのプロセスが終了されるか?というのは「oom_adj_score」という重みづけで確定されます。

出典:ローメモリーキラー(LMK) | App quality | Android Developers
(2025年11月17日閲覧)

上から順番に重みが高い(優先度が高い)です。
基本的にはフォアグラウンドのアプリほど保護され、バックグラウンドのアプリから順に終了されます。
重み付はユーザーへの影響が少ない順(つまりUXに響きにくい)へ沿って行われていますね。

なぜメモリ管理が必要か

メモリ管理の目的はマシンのリソースを効率的かつ安全に使用するためです。
観点について整理しましょう。(Android端末を例に)

⭐️ 効率性の観点
メモリ節約:不要なオブジェクトを解放し限られたRAMを効率的に利用
パフォーマンス:メモリが不足するとGCやkswapd/lmkが発生
バッテリー消費削減:GCやkswapd/lmkの頻発や不要なメモリ確保はバッテリー消費量上昇に影響

⭐️ 安全性の観点
クラッシュ防止:OutOfMemoryErrorの発生防止
アプリの安定性1:lmkを最小限に抑制
アプリの安定性2:メモリ関連による再現性の低いバグを抑制

まとめ

本記事では以下を理解しました:

・1アプリ=1プロセス
・ヒープは可変サイズを置ける上にO(1)でアクセス可能
・メモリ管理はヒープ/ページ/プロセス単位に分かれる
・kswapdでは使わないページはzRAMに退避
・lmkではバックグラウンド寄りのプロセスからキルされる
・メモリ管理は効率性および安全性の観点から重要

以上をここで知ってもらえればと思います!!
次回はGCの仕組みについて記載していく予定です!!
具体的には到達可能性やGC Roots、参照の種類などを扱います。
お楽しみに〜!

帰属表示:
このページの一部は、Androidオープンソースプロジェクトによって作成及び共有された作品から複製されており、クリエイティブ・コモンズ2.5表示ライセンスに記載されている条件に従って使用されています。

2025年12月3日 【Android – メモリ管理①】メモリ管理の全体像を理解する

Category モバイル

ご意見・ご相談・料金のお見積もりなど、
お気軽にお問い合わせください。

お問い合わせはこちら