26
日本Androidの会 日高正博 1

新版 OutOfMemoryErrorを知る

  • Upload
    mhidaka

  • View
    13.090

  • Download
    6

Embed Size (px)

DESCRIPTION

2013年5月6日に横浜Android and モバイルOS プラットフォーム部で発表した資料です。Androidアプリ開発者向けにOutofMemoryErrorの発生原理とメモリ管理について最新事情を加味してまとめました。Androidアプリにおけるメモリ事情は(初期に比べたら)改善していますが、OpenCVなど画像処理の需要、高解像度対応を踏まえると依然として十分とは言いがたいユースケースもあります。そんな中でメモリ資源をうまく使うための指標となれば幸いです。

Citation preview

Page 1: 新版 OutOfMemoryErrorを知る

日本Androidの会 日高正博

1

Page 2: 新版 OutOfMemoryErrorを知る

組込エンジニアです Androidとか。関西が生息圏でした。

techbooster.org みてね

本もあるよ

2

Twitter Account @mhidaka

Page 3: 新版 OutOfMemoryErrorを知る

2010年5月の関西支部勉強会での発表が初版 ◦ 思いのほか「OutOfMemoryErrorを知る」PDFが浸透してた。 古い内容、補足したい項目が多い さすがに3年経つと…というわけで再度まとめました。

ARが流行する兆し ◦ Androidの性能は向上、以前よりOOMは発生しにくい

◦ 性能向上はOpenCVなど画像処理の利用を推進 今でもメモリ管理は重要な技術

3

Page 4: 新版 OutOfMemoryErrorを知る

4

Page 5: 新版 OutOfMemoryErrorを知る

Androidのメモリ管理 Androidのメモリ管理

• Dalvik VM、Linuxのメモリ管理の役割分担

• Java HeapとNative Heapの考え方

• AndroidのGC、Java Heap量の情報

メモリ使用の最適化 メモリ使用の最適化

• Bitmapを使う上での注意点と最適化手法

•アクティビティ、ライフサイクルのメモリリーク予防法(未完)

• OOMさせないキャッシュシステム(未完)

5

Page 6: 新版 OutOfMemoryErrorを知る

6

Page 7: 新版 OutOfMemoryErrorを知る

メモリ不足に陥ったときに発生 ◦ エラー発生は即死せざるを得ない。プログラマの敵。

7

05-14 17:16:45.035: INFO/ActivityManager(51): Config changed: { scale=1.0 imsi=310/260 loc=en_US touch=3 keys=2/1/2 nav=3/1 orien=1 layout=18} 05-14 17:16:45.075: ERROR/dalvikvm-heap(187): 2457600-byte external allocation too large for this process. 05-14 17:16:45.075: ERROR/(187): VM won't let us allocate 2457600

bytes…省略… 05-14 17:16:45.204: ERROR/AndroidRuntime(187): java.lang.OutOfMemoryError: bitmap size exceeds VM budget

OOMを回避するにはAndroidのメモリ管理を知る OOMを回避するにはAndroidのメモリ管理を知る

Page 8: 新版 OutOfMemoryErrorを知る

レジスタベースの仮想マシン レジスタベースの仮想マシン

• Dan Bornsteinおよび Google 社のエンジニアによりAndroidプラットフォームのために

設計・開発

低メモリ環境に対して最適化 低メモリ環境に対して最適化

•システムプロセス Zygoteによる効率的なVMインスタンス作成

VMインスタンスの同時起動 VMインスタンスの同時起動

•プロセス分離(サンドボックス)/メモリ管理/スレッドサポート

Java VM? Java VM?

•動作するバイトコードがJavaバイトコードではない

•独自のDex形式。厳密にはJVMではない

8

Wikipedia:dalvik

Page 9: 新版 OutOfMemoryErrorを知る

JavaHeap ◦ アプリ(VM)ごとに管理される ◦ VM内でスレッドを作った場合は スレッドでも共有されるメモリ空間

◦ (※システム依存)

NativeHeap ◦ JITコンパイル展開用バッファや ◦ DalvikVMsystemの利用

Linux ◦ アプリからはアクセスできない特別な メモリ領域。Kernel空間

2010/5/15 9 日本Androidの会/日高正博

インスタンス化したObj

Java Heap

クラス インスタンス化したObj

NativeHeap

Jitバッファ Dalvik VM利用分

Linux

Kernel空間

メモリ管理 概念図

Page 10: 新版 OutOfMemoryErrorを知る

10

インスタンス化したObj

Java Heap

クラス インスタンス化したObj

NativeHeap

Jitバッファ Dalvik VM利用分

Linux

Kernel空間

メモリ管理 概念図

<管理可能領域> Dalvikからみて管理可能なメモリ領域。 =Java Heap

<管理不可> DalvikからみてGC対象外領域。 =NativeHeap+System Area

管理不可部分を指して NativeHeapもあるので注意

管理不可部分を指して NativeHeapと書く記事もあるので注意

<ユーザー空間> Linuxからみてプロセスごと管理されるメモリ領域

<カーネル空間> Linuxカーネルが管理するメモリ空間

プロセスがKillされたら

占用していたメモリ(ユーザー空間)は解放される

プロセスがKillされたら

占用していたメモリ(ユーザー空間)は解放される

アプリ層から見ると カーネルから見ると

Page 11: 新版 OutOfMemoryErrorを知る

ユーザー空間

Androidアプリ

(プロセスA)

JavaHeap

NativeHeap

Androidアプリ

(プロセスB)

JavaHeap

NativeHeap

Dalvik

(プロセスC)

Dalvik

管理Heap

Linuxアプリ

(プロセスD)

Heap

11

Linuxカーネル空間

Page 12: 新版 OutOfMemoryErrorを知る

マークスイープGC(BitmapMarking手法) ◦ 3つのフェーズでメモリを管理

マーク ◦ オブジェクト使用をマーク用テーブルで管理

スイープ ◦ 未使用オブジェクトがあれば掃除する

アロケーション ◦ メモリ確保要求にあわせて空き容量を探す

12

05-14 17:43:25.916: DEBUG/dalvikvm(51): 05-14 17:43:25.916: DEBUG/dalvikvm(51): GC freed 637 objects / 29528 bytes in 86ms

Page 13: 新版 OutOfMemoryErrorを知る

GC実装 ◦ Full GCからコンカレントGCに変更(Android 2.3)

“Stop the World”の短縮

端末性能の向上に伴い、Java Heap領域が拡張 ◦ 初期heapサイズ(2MB)から ◦ Android 1.x (G1) : 16MB ◦ Android 2.x (Droid, other) : 24MB / 32MB

◦ Android 3.x (Xoom) :48MB ◦ Android 4.x (Galaxy Nexus) :64MB ◦

◦ ※あくまでJava Heapのサイズです。Native Heapについて Dalvikは関知していない(Linuxがプロセスごとに管理)

13

Page 14: 新版 OutOfMemoryErrorを知る

HoneyComb(API Level 11)以降で使用可能 ◦ メモリを大量に消費するアプリのために用意

Java Heapを拡張 ◦ 最大256MB(Android 4.xの場合。システム依存)

14

AndroidManifest.xml

android:largeHeap="true"

ActivityManager am = (ActivityManager)getSystemService(Activity.ACTIVITY_SERVICE); int heapSize = am.getLargeMemoryClass(); int largeHeapSize = am.getLargeMemoryClass(); Log.d("heap","Normal:" + heapSize + " Large:" + largeHeapSize);

Sample

http://developer.android.com/reference/android/app/ActivityManager.html

Page 15: 新版 OutOfMemoryErrorを知る

Java Heapのサイズ Java Heapのサイズ

•初期サイズが2MB、最大サイズが16~64MB(※システム依存)

•Android 3.x~ ではlargeHeapが存在、256MBまで拡張

OutOfMemoryErrorの条件 OutOfMemoryErrorの条件

•メモリアロケーション時に不足を検出したらスローされる。

Java Heap内で(GCしても)要求サイズ分の空きが無ければ発生

JNIでのメモリリソース消費 JNIでのメモリリソース消費

•JNI内のメモリ確保はJava Heapは利用せずにNative Heapが消費される

•Dalvikでは管理できず、開発者がmalloc/freeする

15

Page 16: 新版 OutOfMemoryErrorを知る

解析と最適化アプローチ

16

Page 18: 新版 OutOfMemoryErrorを知る

18

android-sdk¥tools¥ddms.bat

Page 19: 新版 OutOfMemoryErrorを知る

Android 3.x以降、BitmapはJava Heapで確保 ◦ Android 2.3まではNative Heapで確保していた

変更によるメリット ◦ DDMSによるJava Heap解析の対象になる

19

Page 21: 新版 OutOfMemoryErrorを知る

Free up the memory associated with this bitmap's pixels, and mark the bitmap as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing.

isRecycled() Returns true if this bitmap has been recycled.

「今は使わない」というタイミングで呼んでおくと メモリが不足したときに自動的に解放してくれる

21

Page 22: 新版 OutOfMemoryErrorを知る

nativeDecodeStream - doDecode

- decoder->decode(stream, bitmap, prefConfig, decodeMode)

22

SkJPEGImageDecoder::onDecode - this->allocPixelRef(bm, NULL) - SkBitmap::allocPixels - HeapAllocator::allocPixelRef - sk_malloc_flags(size.get32(), 0)

sk_malloc_flags - void* p = malloc(size);

Page 23: 新版 OutOfMemoryErrorを知る

javaBitmap = env->GetObjectField(options, gOptions_bitmapFieldID);

nativeDecodeStream - doDecode

- decoder->decode(stream, bitmap, prefConfig, decodeMode, javaBitmap != NULL))

23

Page 24: 新版 OutOfMemoryErrorを知る

Bitmapの取り扱い

• Recycle/IsRecycle を活用

• BitmapFactory.Options. inPurgeable

• Bitmap.Config に ARGB_8888 からRGB_565 にするだけでメモリ使用量半分に。

画像リソース一般

•画像など大きなリソースはDrawableをデバイスごとに用意。

大画面向けのリソース(xxhdpiなど)の縮小処理はメモリを余分に使う

• JavaHeapは使い終わったオブジェクト参照を残さない

→ setDrawableメソッドのnull代入

→ Activityコンテキストを使いまわさない(Applicationコンテキストで代用)

• System.gc()をおまじないに使う

24

Page 25: 新版 OutOfMemoryErrorを知る

25

GC Bitmap LargeHeap HeapSize LruCache

1.5 Full GC Native × 16MB

1.6 Full GC Native × 16MB ○(SupportLib)

2.x Full GC Native × 24,32MB ○(SupportLib)

2.3 Concurrent GC Native × 48MB ○(SupportLib)

3.X Concurrent GC Java Heap ○(256MB) 48MB ○

4.x Concurrent GC Java Heap ○(256MB) 64MB ○

5.x

Page 26: 新版 OutOfMemoryErrorを知る

ご清聴ありがとうございました

◦ 他にも書きたかったこと

メモリリークの考え方

エラーは取りましょう、とかく(捕まえてエラーを修正するための情報とする)

Activityライフサイクル

メモリリークのおきやすい箇所 ライフサイクル、コンフィグの注意する箇所

onLowMemoryが追加

WeakRefの弱体化とLruCacheの使用推奨

キャッシュの考え方

26