1

更新 - 以下の冗長性を許してください。可能な限り簡潔に言えば、これは次のように動作します。

try {
    mArrowBitmap = BitmapFactory.decodeFile(nam);
} catch(OutOfMemoryError e) {
    Log.e(TAG, "OUT OF MEMORY ERROR!!! ["+e+"]");
}

つまり、外部ヒープが使い果たされると OOME がスローされます。そして、それをキャッチして、単体テストで使用できます。

ただし、これは誤動作します。

try {
    mArrowDrawable = new BitmapDrawable(mContext.getResources(), mArrowBitmap);
} catch(OutOfMemoryError e) {
    Log.e(TAG, "OUT OF MEMORY ERROR!!! ["+e+"]");
}

それは本当に印象的なスップクを実行することを意味します. 私にできることは、そのポケットを調べて緩い小銭を探すことだけです。

そして、より多くの時間を手にする人のために。. .

問題: 多くのビットマップがあり、一部はリソースから、一部は外部からロードされています。デバイスでやむを得ない操作を行います (つまり、前もって行うことができない操作やサーバー側で行う操作など)。ロード中のどこかで、少なくとも 1 つのメモリ リークが発生しました。私はそれを追い求め、有能なふりをしています (そして、DDMS/MAT を見つめるのに多くの時間を費やしています)。SO に関する多くのコメントのおかげで、少なくともビットマップに関する基本的な調査、特にハニカム以前の場所に関する調査を行いました。私のアプリはハニカムとフォワードで正常に動作します。ジンジャーブレッドではうまく動作しません。どちらでもいい

(a) Honeycomm and forward は最終的にヒープ メモリを再利用するため、メモリ リークを無視し、代わりに地球上のすべての人に Gingerbread の使用をやめるように働きかけます。

(b) メモリ リークを分離してつぶします。

オプション (b) の方が優れているようです。

.xmlGingerbread では、ビットマップのネイティブの「バッキング」メモリ (またはをロードするときにシステムが不思議なことに作成するものを含むDrawables) がすべて Dalvik ヒープの外にあることを理解しています。さらに、Dalvik ヒープ上の唯一のものは、そのネイティブ バッキング メモリへの (比較的) 小さなポインターであることも理解しています。リソースを解放しようとすると、作成したすべてのビットマップを見つけて、同期を行う必要がありrecycleます。これに対する私のスキーム fwiw は、ビットマップを作成するときにすべてのビットマップを単純なベクターに「登録」し、そのベクターを繰り返して、ネイティブ バッキング メモリ内のビットマップに似たものをリサイクルすることです。

このため、手元に十分なメモリがあるという Dalvik ヒープからのさまざまなレポートに悩まされることはありませんdecodeが、メモリ不足のために呼び出しが失敗します。実際、私は単体テスト活動の一部を、境界を端まで押し上げて、不正行為を行っていないことを確認することに専念しました (そして、将来的にはそうしないことを願っています)。Robolectric は上記で言及したヒープを「見る」ことができないため、「標準」の Android 単体テスト クラスを使用してこれらの単体テストを行います。告白: 私は Robolectric の方がはるかに気に入っています。

ここにたどり着くには長い道のりです:

あまりにも多くのビットマップを作成して、意図的にネイティブの「バッキング」メモリを最後まで実行すると、ほとんどの場合、期待どおりの結果が得られます。OutOfMemoryError. そのエラーをキャッチし、責任を持って行動します (「責任を持って」の値が非常に小さい場合)。

呼び出しに勝った場合Drawable(呼び出しの代わりに、BitmapFactory両方がこの動作を行うこともあります)、エラーまたは例外の代わりに、logcat:

11-17 16:22:39.372: I/dalvikvm-heap(15069): Clamp target GC heap from 33.916MB to 32.000MB
11-17 16:22:39.372: D/dalvikvm(15069): GC_CONCURRENT freed 5K, 39% free 3701K/6023K, external 26854K/27965K, paused 2ms+2ms
11-17 16:22:39.402: D/dalvikvm(15069): GC_EXTERNAL_ALLOC freed 5K, 39% free 3696K/6023K, external 26854K/27965K, paused 36ms
11-17 16:22:39.442: E/dalvikvm-heap(15069): 81796-byte external allocation too large for this process.
11-17 16:22:39.442: E/dalvikvm(15069): Out of memory: Heap Size=6023KB, Allocated=3696KB, Bitmap Size=26854KB, Limit=32768KB
11-17 16:22:39.442: E/dalvikvm(15069): Trim info: Footprint=6023KB, Allowed Footprint=6023KB, Trimmed=404KB
11-17 16:22:39.442: E/GraphicsJNI(15069): VM won't let us allocate 81796 bytes
11-17 16:22:39.462: I/dalvikvm-heap(15069): Clamp target GC heap from 33.912MB to 32.000MB
11-17 16:22:39.462: D/dalvikvm(15069): GC_CONCURRENT freed <1K, 39% free 3696K/6023K, external 26854K/27965K, paused 3ms+2ms

クランプ部分を掴みます。もつれを解くことができないように見えるのは、真ん中の部分を検出する方法です:

11-17 16:22:39.442: E/dalvikvm(15069): Out of memory: Heap Size=6023KB, Allocated=3696KB, Bitmap Size=26854KB, Limit=32768KB

Errorもちろん、DDMS を監視するException. ことで、この悪い動作を手動で確認できます。しかし、単体テストに組み込むことができるように、プログラムで分離する方法がわかりません。もちろん、私のアプリでこの動作をキャッチするのも良いでしょう。そうすれば、ミスが単体テストの難関をすり抜けた場合 (それは (あまりにも頻繁に) 起こります)、アプリが無意識にその靴を踏みにじるのを避けることができます。

Android のメモリの謎を大げさに説明してくれた熱心な人々に感謝します。まだ読んでいて、私が Android の面白いメモリ構造に戸惑っていた人には、ここから始めることを心からお勧めします。Dubroy 氏の素晴らしいプレゼンテーションです。特に聴衆の質問の最後まで、見る価値があります。最後に、カメラの外にいる人が、これらの同じ不可解な記憶のビットについて、非常に十分な情報に基づいた質問をします.

ここでのガイダンスは、ありがたく受け入れられます。

4

0 に答える 0