question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

OOM & RuntimeException

See original GitHub issue

Description

Hello,

We experienced some OutOfMemoryError and RuntimeException in production. We identified these crashes with crashlytics and we didn’t reach to reproduce it. We think it happens in a RecyclerView with pictures items.

We are using Fresco like this:

val imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)
                        .setProgressiveRenderingEnabled(true)
                        .setRotationOptions(RotationOptions.autoRotate())
                        .setLocalThumbnailPreviewsEnabled(true)
                        .setResizeOptions(ResizeOptions.forDimensions(width, height))
                        .build()
val pipelineDraweeControllerBuilder = Fresco.newDraweeControllerBuilder()
                            .setOldController(frescoImageView.controller)
                            .setControllerListener(object : BaseControllerListener<ImageInfo>() {
                                override fun onIntermediateImageSet(id: String?, imageInfo: ImageInfo?) {
                                    super.onIntermediateImageSet(id, imageInfo)
                                    // Call some callbacks
                                }
                                override fun onFinalImageSet(id: String?, imageInfo: ImageInfo?, animatable: Animatable?) {
                                    super.onFinalImageSet(id, imageInfo, animatable)
                                    // Call some callbacks
                                }
                                override fun onIntermediateImageFailed(id: String?, throwable: Throwable?) {
                                    super.onIntermediateImageFailed(id, throwable)
                                    // Call some callbacks
                                }
                                override fun onFailure(id: String?, throwable: Throwable?) {
                                    super.onFailure(id, throwable)
                                    // Call some callbacks
                                }
                            })
                            .setImageRequest(imageRequest)
drawee.hierarchy.actualImageScaleType = ScalingUtils.ScaleType.FIT_CENTER
drawee.controller = pipelineDraweeControllerBuilder.build()

Here is the stacktrace of the crashes:

Fatal Exception: java.lang.OutOfMemoryError: Failed to allocate a 71615252 byte allocation with 16772848 free bytes and 158MB until OOM
       at dalvik.system.VMRuntime.newNonMovableArray(VMRuntime.java)
       at android.graphics.Bitmap.nativeCreate(Bitmap.java)
       at android.graphics.Bitmap.createBitmap(Bitmap.java:939)
       at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
       at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
       at com.facebook.imagepipeline.memory.BitmapPool.alloc(SourceFile:51)
       at com.facebook.imagepipeline.memory.BitmapPool.alloc(SourceFile:26)
       at com.facebook.imagepipeline.memory.BasePool.get(SourceFile:255)
       at com.facebook.imagepipeline.platform.ArtDecoder.decodeStaticImageFromStream(SourceFile:147)
       at com.facebook.imagepipeline.platform.ArtDecoder.decodeJPEGFromEncodedImage(SourceFile:127)
       at com.facebook.imagepipeline.decoder.DefaultImageDecoder.decodeJpeg(SourceFile:173)
       at com.facebook.imagepipeline.decoder.DefaultImageDecoder$1.decode(SourceFile:56)
       at com.facebook.imagepipeline.decoder.DefaultImageDecoder.decode(SourceFile:119)
       at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder.doDecode(SourceFile:254)
       at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder.access$300(SourceFile:113)
       at com.facebook.imagepipeline.producers.DecodeProducer$ProgressiveDecoder$1.run(SourceFile:152)
       at com.facebook.imagepipeline.producers.JobScheduler.doJob(SourceFile:202)
       at com.facebook.imagepipeline.producers.JobScheduler.access$000(SourceFile:22)
       at com.facebook.imagepipeline.producers.JobScheduler$1.run(SourceFile:73)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at com.facebook.imagepipeline.core.PriorityThreadFactory$1.run(SourceFile:51)
       at java.lang.Thread.run(Thread.java:818)
Fatal Exception: java.lang.RuntimeException: Canvas: trying to draw too large(144609280bytes) bitmap.
       at android.view.DisplayListCanvas.throwIfCannotDraw(DisplayListCanvas.java:260)
       at android.graphics.Canvas.drawBitmap(Canvas.java:1420)
       at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:545)
       at com.facebook.drawee.drawable.ForwardingDrawable.draw(SourceFile:145)
       at com.facebook.drawee.drawable.ForwardingDrawable.draw(SourceFile:145)
       at com.facebook.drawee.drawable.ScaleTypeDrawable.draw(SourceFile:123)
       at com.facebook.drawee.drawable.FadeDrawable.drawDrawableWithAlpha(SourceFile:302)
       at com.facebook.drawee.drawable.FadeDrawable.draw(SourceFile:289)
       at com.facebook.drawee.drawable.ForwardingDrawable.draw(SourceFile:145)
       at com.facebook.drawee.generic.RootDrawable.draw(SourceFile:81)
       at android.widget.ImageView.onDraw(ImageView.java:1268)
       at android.view.View.draw(View.java:18319)
       at android.view.View.updateDisplayListIfDirty(View.java:17297)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.View.draw(View.java:18081)
       at android.view.ViewGroup.drawChild(ViewGroup.java:3966)
       at android.support.design.widget.CollapsingToolbarLayout.drawChild(SourceFile:324)
       at android.view.ViewGroup.dispatchDraw(ViewGroup.java:3752)
       at android.view.View.draw(View.java:18322)
       at android.support.design.widget.CollapsingToolbarLayout.draw(SourceFile:286)
       at android.view.View.updateDisplayListIfDirty(View.java:17297)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3950)
       at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3930)
       at android.view.View.updateDisplayListIfDirty(View.java:17260)
       at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:666)
       at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:672)
       at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:780)
       at android.view.ViewRootImpl.draw(ViewRootImpl.java:3112)
       at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2908)
       at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2502)
       at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1509)
       at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7051)
       at android.view.Choreographer$CallbackRecord.run(Choreographer.java:927)
       at android.view.Choreographer.doCallbacks(Choreographer.java:702)
       at android.view.Choreographer.doFrame(Choreographer.java:638)
       at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:913)
       at android.os.Handler.handleCallback(Handler.java:751)
       at android.os.Handler.dispatchMessage(Handler.java:95)
       at android.os.Looper.loop(Looper.java:154)
       at android.app.ActivityThread.main(ActivityThread.java:6692)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)

Additional Information

For OOM :

  • Android 5 & 6

For RuntimeException:

  • Android 7 & 8

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:6 (1 by maintainers)

github_iconTop GitHub Comments

6reactions
jaksabcommented, Jun 15, 2018

I got OOM often before, now I found solution and use him in all my projects:

  1. In Application class:
 private final FrescoMemoryTrimmableRegistry frescoMemoryTrimmableRegistry = new FrescoMemoryTrimmableRegistry();

@Override
    public void onTrimMemory(final int level) {
        super.onTrimMemory(level);
        switch (level) {
            case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
                frescoMemoryTrimmableRegistry.trim(MemoryTrimType.OnAppBackgrounded);
                L.d("OnAppBackgrounded - level = " + level);
                break;

            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
                frescoMemoryTrimmableRegistry.trim(MemoryTrimType.OnCloseToDalvikHeapLimit);
                clearMemoryCaches();
                L.d("OnCloseToDalvikHeapLimit - level = " + level);
                break;

            case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
            case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
            case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                frescoMemoryTrimmableRegistry.trim(MemoryTrimType.OnSystemLowMemoryWhileAppInForeground);
                L.d("OnSystemLowMemoryWhileAppInForeground - level = " + level);
                break;

            default:
                L.d("default - level = " + level);
                break;
        }
    }

Init Fresco:

ImagePipelineConfig config = ImagePipelineConfig.newBuilder(this)
                .setDownsampleEnabled(true)
                .setResizeAndRotateEnabledForNetwork(true)
                .setBitmapsConfig(Bitmap.Config.RGB_565)
                .setMainDiskCacheConfig(diskCacheConfig)
                .setMemoryTrimmableRegistry(frescoMemoryTrimmableRegistry)
                .setPoolFactory(poolFactory)
                .build();
        Fresco.initialize(this, config);
  1. You have to clean memory when you finish work with some projects screens, resources and when system call to public void onLowMemory() and in other cases which you should know in your project.

  2. If possible, don’t store large pictures on the server. Use the cut-down versions on the lists, and use full quality only on full-screen view.

  3. Use ImageRequest in where you can. Especially on avatars and small views. Calculate the optimal size of picture for a particular device on the client.

For example:

ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                    .setRotationOptions(RotationOptions.autoRotate())
                    .setResizeOptions(new ResizeOptions(recommendedImgSize, recommendedImgSize))
                    .build();
            controller = Fresco.newDraweeControllerBuilder()
                    .setImageRequest(request)
                    .setTapToRetryEnabled(true)
                    .setOldController(imageView.getController())
                    .build();
  1. Don’t use large placeholders images with alpha channel and other in placeholderImage and failureImage attributes, use lite images with right configuration and size. (I lost twitching on weak devices when I change my placeholders).
0reactions
seecaoxingcommented, Aug 9, 2021

why don’t use setRegisterLruBitmapPoolAsMemoryTrimmable method set lrubitmappool tks

Read more comments on GitHub >

github_iconTop Results From Across the Web

Memory Management (OOM) : java.lang.RuntimeException
When a user clicks on an image on the main activity, it gets position of the item and call another url to load...
Read more >
3.2 Understand the OutOfMemoryError Exception
One common indication of a memory leak is the java.lang.OutOfMemoryError exception. Usually, this error is thrown when there is insufficient space to allocate ......
Read more >
How to Handle the OutOfMemoryError in Java - Rollbar
A java.lang.OutOfMemoryError is a runtime error in Java which occurs when the JVM is unable to allocate an object due to insufficient space ......
Read more >
index_parallel ingestions failing with OOM - Google Groups
But am getting OOM on the segment merge phase. "errorMsg": "java.lang.RuntimeException: java.util.concurrent.ExecutionException: java.lang.
Read more >
Investment Allocation crashes BG with OOM due to SQL ...
RuntimeException : java.lang.OutOfMemoryError: Java heap space at com.niku.projmgr.service.staffing.job.InvestmentAllocationJob.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found