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.

frequent OOM while using Fresco lib

See original GitHub issue

Description

Am using fresco lib through gradle(1.1.0) for all the Bitmaps handling in our application, after using app for a while it frequently throws OOM, our application deals with lots of images at a time, there might be 8-10 images(not all of same sizes, some cover half of screen while some take only 50-70dp in size) displayed in single screen and all of them are loaded through network using fresco,

most of the Images being used are with scrollable components such as ListView,GridView, RecyclerView, while some images are recycled through our own logic, below is implementation for same.

Note:

  1. Fresco is Initialised using setDownsampleEnabled
  2. All the images being loaded are resized, though some of our images are of type .png but most of them are in format jpeg

Reproduction

Crash LOG


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


[FILL THIS OUT: How can we reproduce the bug? Provide URLs to relevant images if possible, or a sample project.]

Solution

[OPTIONAL: Do you know what needs to be done to address this issue? Ideally, provide a pull request which fixes this issue.]

Additional Information

  • Fresco version: [1.1.0]
  • Platform version: [ Android version 5 and above]

this is how we are initialising fresco.

        ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
        ImagePipelineConfig imagePipelineConfig = ImagePipelineConfig
                .newBuilder(getApplicationContext())
                .setDownsampleEnabled(true)
                .setBitmapMemoryCacheParamsSupplier(new FrescoCacheParams(activityManager))
                .build();

        Fresco.initialize(getApplicationContext(), imagePipelineConfig);

this is how class FrescoCacheParams is defined.

public class FrescoCacheParams implements Supplier<MemoryCacheParams> {


    private ActivityManager activityManager;

    public FrescoCacheParams(ActivityManager activityManager) {
        this.activityManager = activityManager;
    }

    @Override
    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;
            }
        }
    }
}

This is how all of the Images are being loaded, where width and height are actual size of view which will display loaded images.

            ImageRequest request = ImageRequestBuilder.newBuilderWithSource(uri)
                    .setResizeOptions(new ResizeOptions(width, height))
                    .build();
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setOldController(getController())
                    .setImageRequest(request)
                    .build();
            setController(controller);

Below are snippet of our recycling logic, as we have a custom implementation of AdapterView we are taking care of releasing resources.

       // 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);

we are calling above code on all the Drawee's which are used for displaying images within out cards, once they move out of viewable area on our AdapterView

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Comments:15 (4 by maintainers)

github_iconTop GitHub Comments

19reactions
mradzinskicommented, Jul 7, 2017

@nucleartip funny fact is that I come from porting everything from Glide to Fresco given the huge amount of OOM’s Glide gives…

8reactions
mradzinskicommented, Nov 8, 2017

@AlexCJW I don’t think there’s a way of handling an exception raised by the system such as an OOM, and furthermore can’t think of an scenario where your app will be able to respond to a callback after receiving an OOM since that callback itself would also have to consume unavailable memory after all.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Fresco Operation, Programming and Maintenance Manual
Fresco may be located in any position on the nLight link for ... Turn room lighting on/off, activate scenes, master raise/lower lighting level,....
Read more >
Fresco — Android Image Library - Medium
A powerful library for displaying and management of images in an Android App. It can load the image from API(through server), SD-Card storage...
Read more >
Image Loading and Optimization with Cloudinary and Fresco
In Android, working with images (bitmaps) is really difficult because the application runs out of memory (OOM) very frequently.
Read more >
Fresco An image management library. | Fresco
Fresco is a powerful system for displaying images in Android applications. It takes care of image loading and display so you don't have...
Read more >
Loading images for Jetpack Compose using Glide, Coil, and ...
Landscapist is an image loading library for Jetpack Compose. ... To get started, you should set up Fresco with ImagePipelineConfig in your Application...
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