0

現象: まず、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 は減少しないようです!

ここに画像の説明を入力

他にもこの問題に遭遇した人はいますか?

4

2 に答える 2

0

クラスBitmapには、次のように記述されたrecycle()メソッドがあります。

このビットマップに関連付けられたネイティブ オブジェクトを解放します...

この方法の背後にある理由は、Java ヒープとネイティブ コードで使用されるヒープの 2 つのヒープがあるためです。GC は Java ヒープ サイズのみを認識します。GC の場合、ネイティブ ヒープ内の大きなメモリ ブロックを参照しているにもかかわらず、Java ヒープ上のサイズが小さいため、ビットマップは小さなオブジェクトのように見える場合があります。

于 2013-06-03T05:26:27.013 に答える