Android Linuxのプロセスメモリ管理 その1

Androidのメモリ管理について調べていたら、わかりやすいページがあったので翻訳しました。

ここからの文章はYhcting氏のサイトを翻訳し、若干の補足を加えたものです。

原文

まずはじめに、ここではシェルコマンドによる説明は避けます。
なぜなら、この環境下(Android Linux)ではシェル(bash, tcshなど)が完全に機能することを期待出来ないからです。
Linuxのメモリーについて話す前に、メモリーについての基本的な概念について確認しましょう。
(この記事はkernel 2.6.29 について書かれています。)

メモリーには以下の四つのタイプが存在します。
private(heap) clean : アプリケーションに使用される。
private(heap) dirty : ザイゴート(zygote)に割り振られ、クラスオブジェクトなどに使用される。
shared clean : どこからでも使用される。
shared dirty : 起動中アプリのクラスオブジェクトなどに使用される。

Cleanとは"システムの実装に影響を与えない"という意味です。
私たちはいつでもこのメモリを破棄出来ます。
通常、きちんとmmap()されたものです。

Dirtyとはその逆を意味します。

※mmap()は新しいマッピングを呼び出し元プロセスの仮想アドレス空間に作成するC言語の関数。

Linuxは仮想メモリを利用します。
既にそれについてはご存知のことと思います。
ではもう一段階先へ進みます。
通常はメモリ管理にはデマンドページングという方式が使用されています。

※メモリ管理についてa詳しく知りたい方は以下が参考になると思います。

Linuxカーネル2.4の設計と実装 メモリ管理(前編)
Linuxカーネル2.4の設計と実装 メモリ管理(後編)

デマンドページングによって、Linuxは本当に必要になるまでRAMを使用しません。
それではどういうことかコードを見てみましょう。

#define _BUFSZ (1024*1024*10)
static int _mem[_BUFSZ];
int main (int argc, char* argv[]){
    int i;
	/* --- (※1) --- */
	for(i = 0; i < _BUFSZ; i ++)
	{
		_mem[i] = i;
	}
    /* --- (※2) --- */
}

わかるでしょうか、sizeof(_mem)では sizeof(int)101024*1024 = 40MB です。
int型は4バイト。
しかし、※1では本当にメモリ確保の要求をしているわけではありません。
だからLinuxはまだRAMに割り当てることはしません。
※2で本当にメモリー確保の要求が発生します。

実際にやってみましょう。
皆さんは既にLinuxにはprocfsがあることを知っていることと思います。
ここからメモリーの情報を含め、たくさんのカーネル情報を得ることが出来ます。
もしLinuxがあれば「cat /proc/meminfo」とコマンドを打ってみると
たくさんのメモリーに関する情報が見れると思います。  
今回はMemTotal、MemFree、Buffers、Cashed以外は無視して下さい。

カーネルソースに書かれた説明を引用します。

MemTotal
全ての使用出来るRAM(物理メモリから予約されたビットとカーネル・バイナリコードが引かれたもの)

MemFree
LowFreeとHighFreeを足したもの。

LowFree
LowMemとは32bitではアドレス0xc0000000~の860MBを指し、
LowMem、HighMemは何にでも使用することが出来ますが、カーネルもまた使用します。
もしもLowMem以外にアクセスすると問題が発生するでしょう。

HighFree
HighMemはユーザが使用するためにあります。
具体的には860MB以上の、またはページ・キャッシュのための全領域です。
カーネルはこのメモリにアクセスするためにちょっとした工夫をしますが、
そのせいでLowMemにアクセスするより時間が掛かります。

Buffers
Buffersは一時的な保管に使用されますが、あまり大きくなってはいけません。

Cashed
Cashedはファイルの読み込んだメモリです。仮想メモリは含みません。

次回に続きます。。。