Androidメモリ管理

android-memory.png

Aseoisのメモリ

普通のPCでは最近は4GBぐらいのメモリが普通なのに対し、
AndroidデバイスのRAMはよくて512MB程度である。
まず、メモリの管理をするには、基本的な型が何バイトなのかを知る必要がある。(いろいろな型のページ参照。)
Javaのだけ抜き出すとこうなる

各型のサイズ

項目 java 値の範囲
boolean型 1byte(VMに依存) true,false
char型 2byte 0~655351
byte型 1byte -128~127
short型 2byte -32768~32767
int型 4byte -2147483648~2147483647
long型 64bit -9223372036854775808~9223372036854775807

boolean型は、trueかfalseしか表現しないくせに8ビットもとってるとは驚きですね。
boolean型の配列なんか作ったら多くのビットが無駄になるので、BitSetというクラスを使うのが良い

メモリの状況を知るためのAPI

ActivityManagerのgetMemoryInfo()
ActivityManagerのgetMemoryClass()
ActivityManagerのgetLargeMemoryClass()
DebugのdumpHprofData()
DebugのgetMemoryInfo()
DebugのgetNativeHeapAllocatedSize()
DebugのgetNativeHeapSize()
ActivityManager am=(ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
ActivityMAnager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
am.getMemoryInfo(memInfo);

Debugを使うと

Debug.MemoryInfo debugMemInfo=new Debug.MemoryInfo();
Debug.getMemoryInfo(debugMemInfo();

メモリの種類

ネイティブメモリDebug getNativeHeapSize() getNativeHeapAllocatedSize() getNativeHeapFreeSize()
ネイティブヒープの総サイズ ネイティブヒープに割り当てられたヒープサイズ ネイティブヒープの空き容量
Javaヒープメモリ Runtime maxMemory() totelMemory() freeMemory ()
どのくらいまでJavaヒープメモリを獲得可能か?2 JVMが割当てたJavaヒープメモリの総サイズ 現在使用可能なヒープメモリ

ヒープメモリってなんだっけ?という人はこちらのページへ

largeheap

Android 3.0.x 11 HONEYCOMB Platform Highlights
以降から追加された。

AndroidManifest.xmlにて

android:largeHeap="true"

もしlargeHeap="true"にしなかった場合、使えるメモリサイズは24MB程度(25165840bytes)

ActivityManager.getLargeMemoryClass()でサイズを確認。

ActivityManager am = ((ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE));
int largeMemory = am.getLargeMemoryClass();

Debugクラスのメモリ取得関数

getNativeHeapAllocatedSize()…ネイティブヒープで割り当てられたメモリサイズを返す
Debug

現在のメモリの状態は/proc/meminfo に書かれている。

詳細はここ
MemTotal メモリ搭載量
MemFree 空きメモリ量
Cached PageCacheのサイズ3

meminfoから情報を取得するコード

 /**
     * 物理空きメモリーの取得
     * @return long
     */
    public static long readAvailMem() {
     byte[] buffer = new byte[1024];
        try {
            long memFree = 0;
            long memCached = 0;
            FileInputStream is = new FileInputStream("/proc/meminfo");
            int len = is.read(buffer);
            is.close();
            final int BUFLEN = buffer.length;
            for (int i=0; i<len && (memFree == 0 || memCached == 0); i++) {
                if (matchText(buffer, i, "MemFree")) {
                    i += 7;
                    memFree = extractMemValue(buffer, i);
                } else if (matchText(buffer, i, "Cached")) {
                    i += 6;
                    memCached = extractMemValue(buffer, i);
                }
                while (i < BUFLEN && buffer[i] != '\n') {
                    i++;
                }
            }
            return memFree + memCached;
        } catch (java.io.FileNotFoundException e) {
        } catch (java.io.IOException e) {
        }
        return 0;
    }
 
    /**
     * 物理合計メモリーの取得
     * @return long
     */
    public static long readTotalMem() {
     byte[] buffer = new byte[1024];
        try {
            long memTotal = 0;
            FileInputStream is = new FileInputStream("/proc/meminfo");
            int len = is.read(buffer);
            is.close();
            final int BUFLEN = buffer.length;
            for (int i=0; i<len && (memTotal == 0); i++) {
                if (matchText(buffer, i, "MemTotal")) {
                    i += 8;
                    memTotal = extractMemValue(buffer, i);
                }
                while (i < BUFLEN && buffer[i] != '\n') {
                    i++;
                }
            }
            return memTotal;
        } catch (java.io.FileNotFoundException e) {
        } catch (java.io.IOException e) {
        }
        return 0;
    }
 
    private static boolean matchText(byte[] buffer, int index, String text) {
        int N = text.length();
        if ((index+N) >= buffer.length) {
            return false;
        }
        for (int i=0; i<N; i++) {
            if (buffer[index+i] != text.charAt(i)) {
                return false;
            }
        }
        return true;
    }
 
    private static long extractMemValue(byte[] buffer, int index) {
        while (index < buffer.length && buffer[index] != '\n') {
            if (buffer[index] >= '0' && buffer[index] <= '9') {
                int start = index;
                index++;
                while (index < buffer.length && buffer[index] >= '0'
                    && buffer[index] <= '9') {
                    index++;
                }
                @SuppressWarnings("deprecation")
                String str = new String(buffer, 0, start, index-start);
                return ((long)Integer.parseInt(str)) * 1024;
            }
            index++;
        }
        return 0;
    }

D/memalloc﹕ ion: Mapped buffer base: size:offset:0 fd:71

こんなログが出た

D/memallocion: Mapped buffer base:0x5ecad000 size:1044480 offset:0 fd:71

このログが出る時は、Out Of memory状態になっているらしい[1]
色々数値が書いてありますが、
base PMEM bufferへのアドレス.
Size サブブロックのサイズ
offset あるサブブロックのスタート位置。
fd or file descriptor, ある特定のbufferにアクセスするのに利用される。

ということは、このログ1個で「サブブロック」1個に関する情報のようだ。

サポートサイト Wikidot.com