私はAndroid 3.1、大きなヒープサイズオプション、約250Mの利用可能なメモリでテストしています。
アプリの設定で [テスト] ボタンを押すたびに次のコードが実行されるように設定しました。
float [][][]foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
bm.recycle();
bm = null;
foo = null;
これには十分なメモリがあります。問題なくボタンを数回押すことができます。
しかし、ボタンを押し続けると、最終的に (20 ヒット未満) OutOfMemory で終了します。[通常は android.graphics.Bitmap.nativeCreate(Native Method)]
他に何も起こっていません。PreferencesActivity を離れる必要はありません。ボタンを押したときにも表示される小さなトーストがあるため、他の UI アクティビティがわずかに実行されています。
これは断片化によるものですか、それとも Android Bitmap コードや GC の恐ろしいバグですか? それとも私は愚かなことをしているだけですか?(バカなことさせてください…)
誰にも回避策がありますか?上記は、ユーザーが呼び出すたびにコードが実行する必要があることをかなり代表しているためです。現在、変数を細心の注意を払ってクリアしているにもかかわらず、数回使用すると終了します。(そして、これは長い間私を夢中にさせてきました!)
[アップデート]
断片化の問題または gc のバグであることを確認しました。ヒープ ダンプが示すように、処理中に約 26M でピークに達するアイドル時 (リークなし) に 5.6M しか使用していません。(また、ネイティブ ヒープは 4M 未満のままです。) 一方、Java ヒープは、テスト デバイスで 280M の制限まで拡張され、その時点で OutOfMemory 例外が発生し始めます。そのため、ピーク時に使用可能なヒープの 10% しか使用していませんが、OutOfMemory が発生しています。
[残念ながら、System.gc() への呼び出しを追加すると、上記の単純なテスト ケースが修正されます。(A) 違いはないはずであり、(B) 実際のコードで既に定期的に呼び出しているため、上記の単純なテスト ケースが単純すぎることを意味するため、残念です。]
他の誰かがこれに遭遇しましたか?回避策はありますか?アプリを再起動する適切な方法はありますか?
[アップデート]
次のバージョンでは、3 ~ 4 回の呼び出し (ボタンの押下) で確実に OutOfMemory が発生します。
float [][][]foo = new float[3][2048][2048];
Bitmap bm = Bitmap.createBitmap(2048, 2048, Bitmap.Config.ARGB_8888);
int []bar = new int[3*2048*2048];
bm.recycle();
bm = null;
System.gc();
foo = null;
System.gc();
bar = null;
System.gc();
メモリ トレースは、ヒープが制限に達して終了するまで、各呼び出しで着実に成長していることを示しています。3 つの割り当てのいずれかを削除すると、均衡に達し、無期限に存続します。最後の gc() 以外をすべて削除すると、わずかに早く終了します。
これはフラグメンテーションの問題であり、gc のバグそのものではありません。誰かがそれを修正する方法を知っているなら、私に知らせてください。int[] 割り当てはビットマップを書き込むためのものであるため、2 次元配列として割り当てるオプションはありません (android ビットマップ ライブラリの制限)。