ひつじのにっき

mhidakaのにっきです。たまに長文、気が向いたとき更新。

最近のAndroid事情に対応した「OutOfMemoryErrorを知る」発表スライドを公開しました

横浜Android and モバイルOS プラットフォーム部で発表した資料です。

資料はAndroidアプリ開発者をターゲットにまとめました。OutofMemoryErrorの発生原理とメモリ管理について最新事情を加味してまとめました(新版、なのはAndroid 1.xのころの発表が古いのにまだ参照されていたりで、さすがに最新事情に合わせて更新したかったのです)。


Androidアプリにおけるメモリ事情は(初期に比べたら)改善していますが、OpenCVなど画像処理の需要、高解像度対応を踏まえると依然として十分とは言いがたいユースケースもあります。そんな中でメモリ資源をうまく使うための指標となれば幸いです。

資料にもある通り書きかけの状態ですのでコメントやmentionなど「こんな情報があるから書き加えて」「ここ調べて」「こういうのがおすすめ」「ここ間違えてる!」というご意見いただければ嬉しいです。

少し補足です。

Android 3.x以降、Bitmapの読み込みにJavaHeapを利用するようになったなど一時期に比べてメモリ使用量の解析は行いやすくなっています。こうしてみるとBitmap#recycle()などが一層頼りがいあるように見えるのですが、自動的に行われるといってもメモリの解放/確保にはそれなりの時間がかかります。パフォーマンス的に厳しいAR系だとつらみが増すかもしれません。

LargeHeapももう暫くすると(Android 4.xのシェアが伸びて)メインストリームをすべてカバーできるようになれば画像処理などに便利です。しかし、最大メモリサイズが増えるだけでメモリの拡張段階(まだMaxに到達していない状態)では使い切ったら都度GCが新しいメモリを確保するまで待たねばなりません(JavaHeapを使い切れば都度、GCさんがメモリに空きはないよね?と確認するので時間的デメリットがある)。

当然ながら確保メモリが増えれば増えるほどGCに時間(ストップ・ザ・ワールドの時間が長くなる)がかかります。
さらにコンカレントGCになってからは積極的にGCが走る(もちろんバックグラウンドでアプリと並行して、ですが)フルGCの頃に比べてSystem.gc()の加護も薄くなっています。

JNI経由でnative層におりてメモリを確保するのも一つの手立てです。しかしNativeとJavaのハイブリッドメモリ管理は、アプリが作りたいのかメモリ管理がしたいのか分からなくなるほど、めんどくさいです(少なくともJavaで完結しているときほど気軽ではない)。

資料では書ききれていませんでしたが現在、メモリキャッシュについてはSoftReferenceではなくLruCacheが主流になっています。Android 2.3系でコンカレントGCが採用されたころからの流れで、LruCacheクラスはv4 Support Libraryを使えばAndroid 1.6(!)までバックポートされてますので使わない手はないですね。

アプリケーションのチューニングではOOMの発生とGCによるパフォーマンス低下がセットで言われることが多い(気がする)のでメモリ食いのアプリを作る場合は頭の痛い問題です。
Webを調べてもどのAndroidバージョンをターゲットにした記事かわからず、鵜呑みにできない怖さもあります(情報が古くなってしまっているなど…)再度、ベストプラクティスを集めておきたい今日この頃、とおもって資料を作りました(が、すでに足りない情報があったので補足した次第です…)。