アプリケーションで処理するすべてのビットマップにgradle( 1.1.0
)を介してfresco libを使用しています。しばらくの間アプリを使用すると、頻繁にOOMがスローされますが、アプリケーションは一度に多数の画像を処理します。 10枚の画像(すべて同じサイズではなく、画面の半分をカバーするものもあれば、50〜70dpのサイズしか使用しないものもあります)が1つの画面に表示され、すべてがフレスコ画を使用してネットワーク経由で読み込まれます。
使用されている画像のほとんどは、ListView、GridView、RecyclerViewなどのスクロール可能なコンポーネントを使用していますが、一部の画像は独自のロジックを介してリサイクルされます。以下はその実装です。
ノート:
setDownsampleEnabled
を使用して初期化されますresized
ですが、一部の画像は.png
タイプですが、ほとんどの画像はjpeg
形式です。クラッシュログ
03-15 22:21:21.199 7035-7203/com.xyz E/AndroidRuntime: FATAL EXCEPTION: Thread-442
Process: com.xyz, PID: 7035
java.lang.OutOfMemoryError: Failed to allocate a 1638412 byte allocation with 589552 free bytes and 575KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:831)
at android.graphics.Bitmap.createBitmap(Bitmap.java:808)
at android.graphics.Bitmap.createBitmap(Bitmap.java:775)
at com.facebook.imagepipeline.memory.BitmapPool.alloc(BitmapPool.java:55)
at com.facebook.imagepipeline.memory.BitmapPool.alloc(BitmapPool.java:30)
at com.facebook.imagepipeline.memory.BasePool.get(BasePool.java:259)
at com.facebook.imagepipeline.platform.ArtDecoder.decodeStaticImageFromStream(ArtDecoder.java:137)
at com.facebook.imagepipeline.platform.ArtDecoder.decodeJPEGFromEncodedImage(ArtDecoder.java:120)
at com.facebook.imagepipeline.decoder.DefaultImageDecoder.decodeJpeg(DefaultImageDecoder.java:183)
at com.facebook.imagepipeline.decoder.DefaultImageDecoder$1.decode(DefaultImageDecoder.java:63)
at com.facebook.imagepipeline.decoder.DefaultImageDecoder.decode(DefaultImageDecoder.java:123)
at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder.doDecode(DecodeProducer.java:239)
at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder.access$200(DecodeProducer.java:111)
at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder$1.run(DecodeProducer.java:144)
at com.facebook.imagepipeline.producers.JobScheduler.doJob(JobScheduler.java:207)
at com.facebook.imagepipeline.producers.JobScheduler.access$000(JobScheduler.java:27)
at com.facebook.imagepipeline.producers.JobScheduler$1.run(JobScheduler.java:78)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at com.facebook.imagepipeline.core.PriorityThreadFactory$1.run(PriorityThreadFactory.java:43)
at java.lang.Thread.run(Thread.java:818)
03-15 22:44:53.849 8055-8055/com.xyz E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xyz, PID: 8055
android.view.InflateException: Binary XML file line #2: Binary XML file line #2: Error inflating class <unknown>
at android.view.LayoutInflater.inflate(LayoutInflater.java:539)
at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
at com.xyz.view.newswipe.view.FbLikesGridView$FbLikesAdapter.onCreateViewHolder(FbLikesGridView.java:195)
at com.xyz.view.newswipe.view.FbLikesGridView$FbLikesAdapter.onCreateViewHolder(FbLikesGridView.java:160)
at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:6319)
at android.support.v7.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:5507)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5392)
at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:5388)
at android.support.v7.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2149)
at android.support.v7.widget.GridLayoutManager.layoutChunk(GridLayoutManager.java:556)
at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1496)
at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:593)
at android.support.v7.widget.GridLayoutManager.onLayoutChildren(GridLayoutManager.java:170)
at android.support.v7.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:3535)
at android.support.v7.widget.RecyclerView.onMeasure(RecyclerView.java:2979)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1112)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:632)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1112)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:632)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:18788)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:715)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:461)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewG
[これを記入してください:どうすればバグを再現できますか? 可能であれば、関連する画像またはサンプルプロジェクトへのURLを提供します。]
[オプション:この問題に対処するために何をする必要があるか知っていますか? 理想的には、この問題を修正するプルリクエストを提供してください。]
これが私たちがフレスコ画を初期化する方法です。
ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
.newBuilder(getApplicationContext())
.setDownsampleEnabled(true)
.setBitmapMemoryCacheParamsSupplier(new FrescoCacheParams(activityManager))
.build();
Fresco.initialize(getApplicationContext(), imagePipelineConfig);
これがクラスFrescoCacheParams
定義方法です。
public class FrescoCacheParams implements Supplier<MemoryCacheParams> {
private ActivityManager activityManager;
public FrescoCacheParams(ActivityManager activityManager) {
this.activityManager = activityManager;
}
<strong i="17">@Override</strong>
public MemoryCacheParams get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
int cacheSize = getMaxCacheSize();
Log.d("####","fresco cache size = " + cacheSize);
return new MemoryCacheParams(cacheSize, 1, 1, 1, 1);
} else {
return new MemoryCacheParams(
getMaxCacheSize(),
256,
Integer.MAX_VALUE,
Integer.MAX_VALUE,
Integer.MAX_VALUE);
}
}
private int getMaxCacheSize() {
final int maxMemory = Math.min(activityManager.getMemoryClass()
* ByteConstants.MB, Integer.MAX_VALUE);
if (maxMemory < 32 * ByteConstants.MB) {
return 4 * ByteConstants.MB;
} else if (maxMemory < 64 * ByteConstants.MB) {
return 6 * ByteConstants.MB;
} else {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD) {
return 8 * ByteConstants.MB;
} else {
return maxMemory / 6;
}
}
}
}
これは、すべての画像が読み込まれる方法です。ここで、 width
とheight
は、読み込まれた画像を表示する実際のビューのサイズです。
ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
.setResizeOptions(new ResizeOptions(width, height))
.build();
DraweeController controller = Fresco.newDraweeControllerBuilder()
.setOldController(getController())
.setImageRequest(request)
.build();
setController(controller);
以下は、リソースの解放を担当しているAdapterView
カスタム実装があるため、リサイクルロジックのスニペットです。
// calling on each Drawee, once it moves out of visible area
if (getController() != null) {
getController().onDetach();
}
````
// once a image moves out of display area, we are evicting it out of pipeline as well.
ImagePipeline imagePipeline = Fresco.getImagePipeline();
Uri uri = Uri.parse(url);
imagePipeline.evictFromMemoryCache(uri);
`` `
AdapterView
の表示可能領域から移動すると、アウトカード内の画像を表示するために使用されるすべてのDrawee's
で上記のコードを呼び出します。
こんにちは@nucleartip 、バグレポートを提出してくれてありがとう!
OOMが発生する前にメモリダンプをキャプチャして、すべてのメモリを使用しているものを確認しましたか?
ちなみに、Lollipop以上の場合、maxCacheEntrySize = 1を使用していますが、これはメモリキャッシュを完全に無効にする試みですか、それとも単一のアイテムに制限する試みですか?
@erikandreの大きなキューサイズは、さらに頻繁にOOMをスローしていたため、メモリキャッシュを実質的に無効にするために、キャッシュエントリを少なくしました。
ダンプを取得させてください。ただし、このOOMは、Samsung S7、最新のNexusシリーズの電話などの新世代のデバイスで発生しているため、いずれにせよ、この回避策を提案できますか。
@erikandreは、OOMが原因でアプリがクラッシュする直前に取得されたメモリダンプのスナップショットです。
@nucleartip 、そのメモリダンプを私と共有することは可能でしょうか?
@erikandreヒープダンプのサイズは約250MBですが、ドライブとドロップボックスのどちらがいいですか?
@nucleartipどちらでも問題なく動作します:)
これはもう解決されましたか? 同じ問題があります。
EclipseMemoryAnalyzerでメモリダンプを確認しました。
byte []も多すぎました。
しかし、GCへのパスを使用すると、参照が見つかりません。
これらは、NativePooledByteBufferやNativeMemoryChunkなどのネイティブから参照されているようです。
それらはcom.facebook.common.references.SharedReference.sLiveObjectsにあると思いましたが、証拠がありません。
そして、なぜそれらがリリースされないのか分かりません...
この問題は解決できませんでした。
同じ問題が発生しました。例外情報は次のとおりです。
E/AndroidRuntime: FATAL EXCEPTION: Thread-5458 Process:
package-name, PID: 4877
java.lang.OutOfMemoryError: Failed to allocate a 2560012 byte allocation with 1782384 free bytes and 1740KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:843)
at android.graphics.Bitmap.createBitmap(Bitmap.java:820)
at android.graphics.Bitmap.createBitmap(Bitmap.java:787)
at com.facebook.imagepipeline.memory.BitmapPool.alloc(BitmapPool.java:55)
at com.facebook.imagepipeline.memory.BitmapPool.alloc(BitmapPool.java:30)
at com.facebook.imagepipeline.memory.BasePool.get(BasePool.java:260)
at com.facebook.imagepipeline.platform.ArtDecoder.decodeStaticImageFromStream(ArtDecoder.java:137)
at com.facebook.imagepipeline.platform.ArtDecoder.decodeJPEGFromEncodedImage(ArtDecoder.java:120)
at com.facebook.imagepipeline.decoder.DefaultImageDecoder.decodeJpeg(DefaultImageDecoder.java:186)
at com.facebook.imagepipeline.decoder.DefaultImageDecoder$1.decode(DefaultImageDecoder.java:63)
at com.facebook.imagepipeline.decoder.DefaultImageDecoder.decode(DefaultImageDecoder.java:126)
at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder.doDecode(DecodeProducer.java:240)
at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder.access$200(DecodeProducer.java:112)
at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder$1.run(DecodeProducer.java:145)
at com.facebook.imagepipeline.producers.JobScheduler.doJob(JobScheduler.java:207)
at com.facebook.imagepipeline.producers.JobScheduler.access$000(JobScheduler.java:27)
at com.facebook.imagepipeline.producers.JobScheduler$1.run(JobScheduler.java:78)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at com.facebook.imagepipeline.core.PriorityThreadFactory$1.run(PriorityThreadFactory.java:43)
at java.lang.Thread.run(Thread.java:818)
これは、OOMが発生する前のすべてのGC情報です。
I/art: Starting a blocking GC Alloc
I/art: Starting a blocking GC Alloc
I/art: Alloc sticky concurrent mark sweep GC freed 92215(9MB) AllocSpace objects, 36(660KB) LOS objects, 8% free, 117MB/128MB, paused 1.228ms total 37.123ms
I/art: Starting a blocking GC Alloc
I/art: Starting a blocking GC Alloc
I/art: Waiting for a blocking GC Alloc
I/art: Clamp target GC heap from 188MB to 128MB
I/art: Alloc partial concurrent mark sweep GC freed 45395(2MB) AllocSpace objects, 43(860KB) LOS objects, 3% free, 124MB/128MB, paused 727us total 59.648ms
I/art: WaitForGcToComplete blocked for 25.090ms for cause Alloc
I/art: Starting a blocking GC Alloc
I/art: Starting a blocking GC Alloc
I/art: Starting a blocking GC Alloc
W/art: Suspending all threads took: 5.155ms
I/art: Waiting for a blocking GC Alloc
I/art: Alloc sticky concurrent mark sweep GC freed 2803(277KB) AllocSpace objects, 2(40KB) LOS objects, 0% free, 126MB/128MB, paused 579us total 19.249ms
I/art: Starting a blocking GC Alloc
I/art: Waiting for a blocking GC Alloc
I/art: Alloc sticky concurrent mark sweep GC freed 822(87KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 126MB/128MB, paused 547us total 12.316ms
I/art: WaitForGcToComplete blocked for 11.410ms for cause Alloc
I/art: Starting a blocking GC Alloc
I/art: Waiting for a blocking GC Alloc
I/art: Clamp target GC heap from 190MB to 128MB
I/art: Alloc partial concurrent mark sweep GC freed 4725(241KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 126MB/128MB, paused 658us total 46.759ms
I/art: WaitForGcToComplete blocked for 46.699ms for cause Alloc
I/art: Starting a blocking GC Alloc
I/art: Waiting for a blocking GC Alloc
I/art: Clamp target GC heap from 190MB to 128MB
I/art: Alloc concurrent mark sweep GC freed 801(78KB) AllocSpace objects, 0(0B) LOS objects, 0% free, 126MB/128MB, paused 796us total 40.098ms
I/art: WaitForGcToComplete blocked for 35.773ms for cause Alloc
I/art: Starting a blocking GC Alloc
I/art: Forcing collection of SoftReferences for 2MB allocation
I/art: Waiting for a blocking GC Alloc
I/art: Waiting for a blocking GC Alloc
I/art: Clamp target GC heap from 191MB to 128MB
I/art: Alloc concurrent mark sweep GC freed 3661(366KB) AllocSpace objects, 1(20KB) LOS objects, 0% free, 127MB/128MB, paused 634us total 61.758ms
I/art: WaitForGcToComplete blocked for 60.363ms for cause Alloc
I/art: Starting a blocking GC Alloc
I/art: Waiting for a blocking GC Alloc
W/art: Suspending all threads took: 38.816ms
/I/art: Forcing collection of SoftReferences for 2MB allocation
/I/art: Waiting for a blocking GC Alloc
/I/art: Clamp target GC heap from 190MB to 128MB
/I/art: Alloc concurrent mark sweep GC freed 214(8KB) AllocSpace objects, 1(416KB) LOS objects, 0% free, 126MB/128MB, paused 876us total 42.655ms
/I/art: WaitForGcToComplete blocked for 82.057ms for cause Alloc
/I/art: Starting a blocking GC Alloc
/I/art: Starting a blocking GC Alloc
/W/art: Throwing OutOfMemoryError "Failed to allocate a 2560012 byte allocation with 1643888 free bytes and 1605KB until OOM"
/I/art: Waiting for a blocking GC Alloc
/I/art: Clamp target GC heap from 190MB to 128MB
/I/art: Alloc concurrent mark sweep GC freed 12633(1496KB) AllocSpace objects, 0(0B) LOS objects, 1% free, 126MB/128MB, paused 684us total 43.271ms
/I/art: WaitForGcToComplete blocked for 136.549ms for cause Alloc
/I/art: Starting a blocking GC Alloc
/I/art: Waiting for a blocking GC Alloc
/I/art: Waiting for a blocking GC Alloc
/I/art: Forcing collection of SoftReferences for 2MB allocation
/I/art: Waiting for a blocking GC Alloc
/I/art: Clamp target GC heap from 190MB to 128MB
/I/art: Alloc concurrent mark sweep GC freed 2239(265KB) AllocSpace objects, 0(0B) LOS objects, 1% free, 126MB/128MB, paused 1.282ms total 40.182ms
/I/art: WaitForGcToComplete blocked for 120.837ms for cause Alloc
/I/art: Starting a blocking GC Alloc
/I/art: Waiting for a blocking GC Alloc
/I/art: Waiting for a blocking GC Alloc
/I/art: Forcing collection of SoftReferences for 2MB allocation
/I/art: Waiting for a blocking GC Alloc
/W/art: Suspending all threads took: 30.572ms
/I/art: Clamp target GC heap from 190MB to 128MB
/I/art: Alloc concurrent mark sweep GC freed 7(1264B) AllocSpace objects, 0(0B) LOS objects, 1% free, 126MB/128MB, paused 2.697ms total 43.668ms
/I/art: WaitForGcToComplete blocked for 129.040ms for cause Alloc
/I/art: Starting a blocking GC Alloc
/I/art: WaitForGcToComplete blocked for 83.495ms for cause Alloc
/I/art: Starting a blocking GC Alloc
/I/art: Waiting for a blocking GC Alloc
/W/art: Throwing OutOfMemoryError "Failed to allocate a 2560012 byte allocation with 1782384 free bytes and 1740KB until OOM"
/I/art: Waiting for a blocking GC Alloc
/I/art: Waiting for a blocking GC Alloc
1クラッシュする前に、最初のページでViewpager + RecyclerViewページを開きます。
約20枚の写真があります。
2クラッシュする前に、最初の2つでViewpager + RecyclerViewページを開きます。
約40枚の写真があり、ポケットベルの両側にあるViewpagerにはそれぞれ30枚の写真があります。
3クラッシュ後:
私はこれをますます頻繁に見ています、特により多くの利用可能なRAMを備えた新しいデバイスで。 これは、RAM Frescoがより多くのRAMを使用する必要があるようで、OOMの頻度が高くなります。
私の構成はデフォルトの構成です(まだ自分のサプライヤーを実装しようとはしていません)が、それが大いに役立つかどうかは真剣に疑っています(最大キャッシュエントリを0に設定して、キャッシュを完全に無効にしない限り)。
これにどのように取り組むことができるか考えていますか?
@mradzinski結局、完全にGlide
に移植したので、アプリにOOMがないことを宣言しました。
@nucleartip面白い事実は、OOMのGlideが大量に提供することを考えると、GlideからFrescoまですべてを移植することから来ているということです...
調査を続行するための十分な情報がないため、これを閉じます。
その他のメモリ不足の問題については、新しいタスクを作成し、できればHPROFメモリダンプを含めてください。
@erikandre
OOMの問題を解決するのに十分な情報がないことを知っています。 OOMエラーをスローするのではなく、コールバックを使用してエラーイベントを投稿することをお勧めします。 OOMイベントを自分で処理できるようにします。
@AlexCJW OOMなどのシステムによって発生した例外を処理する方法はないと思います。さらに、コールバック以降、OOMを受信した後、アプリがコールバックに応答できるシナリオは考えられません。結局のところ、それ自体も使用できないメモリを消費する必要があります。
最も参考になるコメント
@nucleartip面白い事実は、OOMのGlideが大量に提供することを考えると、GlideからFrescoまですべてを移植することから来ているということです...