低 RAM 設定

Android は 512 MB の RAM を搭載したデバイスをサポートしています。このドキュメントは、OEM が低メモリデバイス向けに Android カーネル 4.4 の最適化と設定を行うのに役立ちます。こうした最適化のいくつかは汎用性があるため、以前のリリースにも適用できます。

Android カーネル 4.4 プラットフォームの最適化

メモリ管理の改善

  • 有効なメモリ節約型カーネル設定: zram にスワップします。
  • キャッシュされていないプロセスが大きすぎる場合、プロセスを強制終了します。
  • 大規模なサービスが A サービスの分類に戻らないようにします(そのためランチャーが強制終了されることはありません)。
  • アイドル時のメンテナンスで大きくなりすぎるプロセスを(現在の IME など通常は強制終了できないものであっても)強制終了します。
  • バックグラウンド サービスの起動をシリアル化します。
  • 低 RAM デバイスのメモリ使用量の調整: メモリ不足(OOM)調整レベルを厳しくし、グラフィック キャッシュを小さくします。

システムメモリの削減

  • system_server プロセスとシステム UI プロセスのトリミング(数メガバイトの節約)。
  • Dalvik の dex キャッシュをプリロードします(数メガバイトの節約)。
  • 有効な JIT-off オプション(プロセスあたり最大 1.5 MB の節約)。
  • プロセスごとのフォント キャッシュ オーバーヘッドの削減。
  • ArrayMap / ArraySet の導入。フットプリントの軽い HashMap / HashSet の代替としてフレームワークで広く使用されます。

Procstats

メモリ状態とアプリのメモリ使用量を、実行頻度とメモリ消費量でランク付けして表示する開発者向けオプションの追加。

API

ActivityManager.isLowRamDevice() の追加。これによりアプリは、低メモリデバイスで実行されていることを検出し、RAM 消費量の多い機能の無効化を選択できます。

メモリのトラッキング

グラフィック メモリの割り当てをトラックする memtrack HAL の追加、dumpsys meminfo の追加情報、meminfo の概要の明確化(たとえば、報告された空き RAM にはキャッシュされたプロセスの RAM が含まれるため、OEM は誤って最適化を試みることはありません)。

ビルド時の設定

低 RAM デバイスフラグ

ActivityManager.isLowRamDevice() フラグは、低メモリデバイスでうまく機能しない、メモリを大量に使用する特定の機能をオフにするかどうかを指定します。

512 MB のデバイスの場合、このフラグは true を返します。これは、デバイス makefile の次のシステム プロパティで有効にできます。

    PRODUCT_PROPERTY_OVERRIDES += ro.config.low_ram=true
    

ランチャー設定

ランチャーのデフォルトの壁紙設定では、ライブ壁紙を使用しないでください。低メモリデバイスには、ライブ壁紙をプリインストールしないでください。

カーネル設定

カーネル / ActivityManager を調整して直接回収を減らす

直接回収は、プロセスまたはカーネルがメモリのページを(直接的に、または新しいページで障害が発生したために)割り当てようとし、カーネルが使用可能な空きメモリをすべて使用したときに発生します。これにより、カーネルはページを解放しつつ、割り当てをブロックする必要があります。そして、ファイル バックアップのダーティページをフラッシュするために、または lowmemorykiller がプロセスを強制終了するまで待つために、ディスク I/O が必要になることがよくあります。その結果、UI スレッドを含むすべてのスレッドで、余分な I/O が発生する可能性があります。

直接回収を回避するため、カーネルには、kswapd またはバックグラウンド回収をトリガーする透かしがあります。これはページを解放しようとするスレッドであり、次回実際のスレッドが割り当てられるとすぐに成功します。

バックグラウンド回収をトリガーするデフォルトのしきい値はかなり低く、2 GB のデバイスで約 2 MB、512 MB のデバイスで 636 KB です。カーネルは、バックグラウンド回収で数メガバイトしかメモリを回収しません。つまり、数メガバイトを超えて迅速に割り当てるプロセスが、すぐに直接回収されます。

カーネル調整パラメータのサポートは、パッチ 92189d47f66c67e5fd92eafaa287e153197a454f として Android-3.4 カーネル ブランチに追加されました(「extra_free_kbytes 調整パラメータの追加」)。このパッチをデバイスのカーネルにチェリーピックすることで、ActivityManager はカーネルに 3 つのフルスクリーン 32 bpp のメモリバッファを空けておくように指示できます。

これらのしきい値は、config.xml フレームワークで設定できます。

    <!-- Device configuration setting the /proc/sys/vm/extra_free_kbytes tunable
    in the kernel (if it exists).  A high value will increase the amount of memory
    that the kernel tries to keep free, reducing allocation time and causing the
    lowmemorykiller to kill earlier.  A low value allows more memory to be used by
    processes but may cause more allocations to block waiting on disk I/O or
    lowmemorykiller.  Overrides the default value chosen by ActivityManager based
    on screen size.  0 prevents keeping any extra memory over what the kernel keeps
    by default.  -1 keeps the default. -->
    <integer name="config_extraFreeKbytesAbsolute">-1</integer>
    
    <!-- Device configuration adjusting the /proc/sys/vm/extra_free_kbytes
    tunable in the kernel (if it exists).  0 uses the default value chosen by
    ActivityManager.  A positive value  will increase the amount of memory that the
    kernel tries to keep free, reducing allocation time and causing the
    lowmemorykiller to kill earlier.  A negative value allows more memory to be
    used by processes but may cause more allocations to block waiting on disk I/O
    or lowmemorykiller.  Directly added to the default value chosen by
    ActivityManager based on screen size. -->
    <integer name="config_extraFreeKbytesAdjust">0</integer>
    

LowMemoryKiller の調整

ActivityManager は、LowMemoryKiller のしきい値を、各優先度のバケットでプロセスを実行するために必要な、ファイル バックアップのページ(キャッシュ ページ)のワーキング セット期待値に一致するように設定します。デバイスのワーキング セットに対する要件が高い場合(たとえばベンダーの UI がより多くのメモリを必要とする場合や、より多くのサービスが追加されている場合)は、しきい値を増やすことができます。

ファイル バックアップのページ用に予約されているメモリが多すぎる場合は、しきい値を減らすことができます。これにより、キャッシュが小さすぎるためにディスク スラッシングが発生するかなり前に、バックグラウンド プロセスが強制終了されます。

    <!-- Device configuration setting the minfree tunable in the lowmemorykiller
    in the kernel.  A high value will cause the lowmemorykiller to fire earlier,
    keeping more memory in the file cache and preventing I/O thrashing, but
    allowing fewer processes to stay in memory.  A low value will keep more
    processes in memory but may cause thrashing if set too low.  Overrides the
    default value chosen by ActivityManager based on screen size and total memory
    for the largest lowmemorykiller bucket, and scaled proportionally to the
    smaller buckets.  -1 keeps the default. -->
    <integer name="config_lowMemoryKillerMinFreeKbytesAbsolute">-1</integer>
    
    <!-- Device configuration adjusting the minfree tunable in the
    lowmemorykiller in the kernel.  A high value will cause the lowmemorykiller to
    fire earlier, keeping more memory in the file cache and preventing I/O
    thrashing, but allowing fewer processes to stay in memory.  A low value will
    keep more processes in memory but may cause thrashing if set too low.  Directly
    added to the default value chosen by          ActivityManager based on screen
    size and total memory for the largest lowmemorykiller bucket, and scaled
    proportionally to the smaller buckets. 0 keeps the default. -->
    <integer name="config_lowMemoryKillerMinFreeKbytesAdjust">0</integer>
    

zram へのスワップ

zram スワップは、メモリページを圧縮し、それを動的に割り当てられるメモリスワップ領域に配置することで、システムで使用可能なメモリ量を増やすことができます。これは CPU 時間と引き換えにメモリを少し増やすものであるため、zram スワップがシステムに与えるパフォーマンス上の影響の測定に注意する必要があります。

Android は複数のレベルで zram へのスワップを処理します。

  • まず、zram スワップを効果的に使用するために、次のカーネル オプションを有効にする必要があります。
    • CONFIG_SWAP
    • CONFIG_CGROUP_MEM_RES_CTLR
    • CONFIG_CGROUP_MEM_RES_CTLR_SWAP
    • CONFIG_ZRAM
  • 次に、下記のような行を fstab に追加します。
        /dev/block/zram0 none swap defaults zramsize=<size in bytes>,swapprio=<swap partition priority>
        
    • zramsize は必須です。zram 領域で保持する非圧縮メモリの量を示します。通常、30~50% の圧縮率が確認されます。
    • swapprio はスワップ領域が複数あるわけではない場合にのみ必要です。

    デバイス固有の sepolicy/file_contexts で関連するブロック デバイスに swap_block_device というラベルを付けて、SELinux によって適切に処理されるようにします。

        /dev/block/zram0 u:object_r:swap_block_device:s0
        
  • デフォルトでは、Linux カーネルは一度に 8 ページのメモリをスワップします。zram を使用する場合、一度に 1 ページ読み取る増分のコストはごくわずかであるため、デバイスのメモリ プレッシャーが極端に高い場合に役立ちます。1 ページずつ読み取るには、init.rc に下記を追加します。
        write /proc/sys/vm/page-cluster 0
        
  • init.rc で、mount_all /fstab.X 行の後に下記を追加します。
        swapon_all /fstab.X
        
  • メモリ cgroup は、カーネルで機能が有効になっている場合、起動時に自動的に設定されます。
  • メモリ cgroup が使用可能な場合、ActivityManager は優先順位の低いスレッドを、他のスレッドよりもスワップ可能であるとマークします。メモリが必要になると、Android カーネルはメモリページを zram スワップに移行し始め、ActivityManager によってマークされたメモリページに高い優先順位を与えます。

カーブアウト、Ion、連続メモリ割り当て(CMA)

低メモリデバイスでは、特に完全には使用されていないカーブアウト(セキュリティ保護された動画の再生のためのカーブアウトなど)に注意することが重要です。ハードウェアの正確な要件に応じて、カーブアウト領域の影響を最小限に抑えるソリューションはいくつかあります。

ハードウェアが不連続なメモリ割り当てを許す場合、Ion システムヒープはシステムメモリからのメモリ割り当てを可能にし、カーブアウトを不要にします。Ion は周辺機器へのトランスレーション ルックアサイド バッファ(TLB)の圧迫をなくすために、大規模な割り当ても試みます。メモリ領域が連続している必要がある場合または特定のアドレス範囲に制限される必要がある場合、CMA を使用できます。

これにより、システムが移動可能なページにも使用できるカーブアウトが作成されます。領域が必要になると移動可能なページがその領域から移行され、システムは、空きがあるとき他の目的のために大きなカーブアウトを自由に使用できます。CMA は Ion CMA ヒープで直接使用できます。

アプリの最適化のヒント

  • アプリのメモリを管理すると、下記のブログ投稿を確認します。
  • development/tools/findunused を使用して、プリインストールされているアプリから未使用のアセットを削除します(これでアプリを小さくできるはずです)。
  • 特に透過領域がある場合は、アセットに PNG 形式を使用します。
  • ネイティブ コードを記述する場合は、malloc / memset ではなく calloc() を使用します。
  • パーセルデータをディスクに書き込んで後で読み取るコードは、有効にしないでください。
  • インストールされているすべてのパッケージに登録するのではなく、SSP フィルタリングを使用します。次のようなフィルタリングを追加します。
        <data android:scheme="package" android:ssp="com.android.pkg1" />
        <data android:scheme="package" android:ssp="com.myapp.act1" />
        

Android のさまざまなプロセス状態について

状態 意味 詳細
SERVICE
SERVICE_RESTARTING
アプリ関連の理由によってバックグラウンドで実行されるアプリ。 SERVICESERVICE_RESTARTING は、アプリをバックグラウンドで実行しすぎると発生する、ごく一般的な問題です。「悪さ」の指標として、%duration * pss または %duration を使用します。このようなアプリをまったく実行しないことが理想的です。
IMPORTANT_FOREGROUND
RECEIVER
バックグラウンドで実行されている(ユーザーと直接やり取りしない)アプリ。 システムにメモリ負荷がかかります。これらのプロセスを順序付けるには、(%duration * pss)「悪さ」の値を使用します。しかし、このようなアプリの多くは正当な理由で実行されます。pss のサイズはメモリ負荷の重要な部分です。
PERSISTENT 永続的なシステム プロセス。 pss をトラックして、これらのプロセスが大きくなりすぎていないか確認します。
TOP ユーザーが現在やり取りしているプロセス。 ここで pss は重要な指標であり、アプリの使用中にどれだけのメモリ負荷が生じるかを示します。
HOME
CACHED_EMPTY
再び必要になった場合に備えてシステムが保持しているプロセス。 これらのプロセスはいつでも自由に強制終了でき、必要に応じて再作成できます。メモリ状態(normal、moderate、low、critical)は、システムが実行しているプロセスの数に基づいて計算されます。これらのプロセスの主要な指標は pss です。この状態で、これらのプロセスは、保持するプロセスの総数を最大にできるように、メモリのフットプリントを可能な限り減らす必要があります。この状態では、正常に動作するアプリは通常、TOP 状態よりも pss フットプリントがかなり小さくなります。
CACHED_ACTIVITY
CACHED_ACTIVITY_CLIENT
TOP と比較すると、アプリがどれだけメモリをバックグラウンドに解放するかがわかります。 CACHED_EMPTY 状態を除外すると、ユーザー操作以外の理由でプロセスが開始された状況が除かれるため、このデータが改善されます。これにより、ユーザー関連アクティビティで CACHED_EMPTY の UI オーバーヘッドの処理が不要になります。

分析

アプリの起動時間の分析

アプリの起動時間を分析するには、$ adb shell am start -P または --start-profiler を実行し、アプリを起動します。プロファイラは、プロセスが Zygote からフォークされた後、コードがフォークに読み込まれる前に開始します。

バグレポートを使用した分析

バグレポートには、batterystatsnetstatsprocstatsusagestats を含め、デバッグに使用できるサービスが複数あります。レポートには次のような行を含めることができます。

    ------ CHECKIN BATTERYSTATS (dumpsys batterystats --checkin) ------
    7,0,h,-2558644,97,1946288161,3,2,0,340,4183
    7,0,h,-2553041,97,1946288161,3,2,0,340,4183
    

永続プロセスの確認

永続プロセスを確認するには、デバイスを再起動してプロセスを確認します。次に、デバイスを数時間動作させ、プロセスを再度確認します。2 つの確認の間に長時間実行プロセスがあってはなりません。

長期間テストの実行

長期間テストを実行するには、デバイスを長時間実行し、プロセスのメモリをトラックして、増加するか一定に保たれるかを判断します。次に、正規のユースケースを作成し、これらのシナリオで長期間テストを実行します。