Androidにおけるガーベジコレクション

android-gc.png

AndroidのGCは重い

GCを実行している間、すべてのスレッドを停止するのだ。
なのでなるべくGCを発生させないことが大事である。

ガーベッジコレクションの起爆剤となる5種類の状況

GC_FOR_MALLOC ヒープがいっぱいでメモリを割り当てることが出来ず、割り当てを実行するにはメモリを回収しなければならない
GC_CONCURRENT 通常は回収するオブジェクトが十分にあるため、(場合によっては部分的な)回収を開始する
GC_EXPLICIT System.gc()を呼び出してガーベジコレクションを明示的にリクエストする
GC_EXTERNAL_ALLOC HoneyComb以降はすべてのオブジェクトがヒープで割り当てられるため、外部メモリ割り当ては起こらない
GC_HPROF_DUMP_HEAP HPROF(Heap/CPU Profiling)ファイルを作成したときに発生する

AndroidではなるべくGCが起きないように工夫する必要がある。

GCが起きると遅いから、避けるためには?
特に、onDrawFrame内では以下のことに気をつけよう

new をしまくらない

  ローカル変数でもnewしたらメモリ割りあて→解放が発生します。
 必要なものはクラスのメンバ変数に突っ込んで使いまわすようにしよう

foreach文を使わない

  foreachはイテレータを生成して処理をするらしいのでメモリ割り当て解放が発生するようです。
  あたしのソースはArrayListを全部foreachで処理してたので全部以下のように書き直しました。

for( UserObject obj : mObjectList)

どこがGCの元凶かチェックするにはAllocation Tracker

     ↓
こちらの方がGCが起きにくい

 for( int i=0; i< mObjectList.size(); i++)

enumクラスを使わない。

  enumクラスもメモリ割り当て→解放が頻発するらしい。
  enumクラスはすべて定数(public static final 型) に書き換え。

描画時にcreateBufferしない。

  前回導入したOpenGLで描画するクラスのとこですが、
  描画前にAllocationBufferでFloat型のバッファを作成しておりました。
  これがかなりメモリ食ってました。
  いいのか悪いのかわかりませんが、これも描画用のオブジェクトにFloatBuffer変数をメンバ変数に定義し
  使いまわすように修正。

さて、デバッグ実行してAllocationTrackerとにらめっこ。
明らかにメモリ解放頻度が減ってます。目に見えて減ってます。
LogcatもGC発生頻度が激減し、画面も止まらなくなりました!

OnDrawFrame内でローカル変数は作らない、メンバ変数にする

GC_FOR_MALLOC?あんなんワンパンOKやww

Mapを使ったオブジェクト使い回し

オブジェクトをMapに入れて使い回すというテクニックを使うことが多い


android-speed dalvik garbage-collection

サポートサイト Wikidot.com android-speeddalvikgarbage-collection