現象: まず、OutOfMemoryError をキャッチするまで Java 側でいくつかの大きなメモリ ブロックを割り当ててから、それらをすべて解放します。ここで、奇妙なことが起こります。BitmapFactory.decodeXXX(decodeResource、decodeFile、...) によって小さな画像 (例: 幅:200、高さ:200) を読み込むと、OutOfMemoryError がスローされます! しかし、純粋な Java ビッグ オブジェクト (たとえば、新しいバイト [2*1024*1024]) を割り当てても問題ありません。
検証: 問題を検証するための簡単なコードをいくつか書きました。ここからダウンロードできます。「Alloc」ボタンを何度も押すと、OOF エラーが発生します。次に、「Free All」を押すと、環境がセットアップされます。ここで「LoadBitmap」を押すと、ほとんどの Android 2.x フォンでは機能しないことがわかります (ただし、エミュレーターでは問題ありませんが、奇妙です)。
より深く掘り下げます: いくつかの dalvik コードを掘り下げて理由を調べ、 dvmTrackExternalAllocation によって呼び出されたHeapSource.cの関数 externalAllocPossible に潜在的なバグを見つけて、LogCat に「このプロセスには xxx バイトの外部割り当てが大きすぎます」というメッセージを出力しようとしました.
externalAllocPossible では、次のように単純に記述しました。
if (currentHeapSize + hs->externalBytesAllocated + n <=
heap->absoluteMaxSize)
{
return true;
}
return false;
つまり、ネイティブ ビットマップの割り当てサイズと currentHeapSize (以下に示すように実際に割り当てられたサイズではありません。この場合、増加したヒープの最大サイズを保持していますが、すべて解放した) が制限を超えると、ネイティブ ビットマップの割り当て常に失敗しますが、 Java オブジェクトのメモリが 91.3% 解放された (null に設定されて GC がトリガーされた) 場合でも、Java の currentHeapSize は減少しないようです!
他にもこの問題に遭遇した人はいますか?