Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Out of memory error #22

Closed
lalith-b opened this issue Sep 11, 2013 · 30 comments
Closed

Out of memory error #22

lalith-b opened this issue Sep 11, 2013 · 30 comments
Labels

Comments

@lalith-b
Copy link

The code on my application class is below.

public void setImageManager(){
    final Glide glide = Glide.get();
    if (!glide.isImageManagerSet()) {
        File cacheDir = ImageManager.getPhotoCacheDir(this, CACHE_NAME);
        DiskCache diskCache;
        try {
            diskCache = DiskLruCacheWrapper.get(cacheDir, 50 * 1024 * 1024);
        } catch (IOException e) {
            e.printStackTrace();
            diskCache = new DiskCacheAdapter();
        }


        ImageManager.Builder builder = new ImageManager.Builder(this);
        builder.decodeBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
        builder.setBitmapCompressFormat(CompressFormat.PNG);
        builder.setDiskCache(diskCache);
        glide.setImageManager(builder);
    }
}

The below is my stacktrace.

09-11 16:57:06.589: E/dalvikvm-heap(14859): Out of memory on a 614860-byte allocation.
09-11 16:57:06.589: I/dalvikvm(14859): "Thread-7971" prio=5 tid=16 RUNNABLE
09-11 16:57:06.589: I/dalvikvm(14859):   | group="main" sCount=0 dsCount=0 obj=0x41806198 self=0x18281d0
09-11 16:57:06.589: I/dalvikvm(14859):   | sysTid=14940 nice=10 sched=0/0 cgrp=bg_non_interactive handle=25318736
09-11 16:57:06.599: I/dalvikvm(14859):   | schedstat=( 1411041240 6718078644 17923 ) utm=104 stm=37 core=0
09-11 16:57:06.709: I/dalvikvm(14859):   at java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:~122)
09-11 16:57:06.849: I/dalvikvm(14859):   at com.android.volley.toolbox.BasicNetwork.entityToBytes(BasicNetwork.java:215)
09-11 16:57:06.859: I/dalvikvm(14859):   at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:104)
09-11 16:57:06.869: I/dalvikvm(14859):   at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)
09-11 16:57:07.119: E/AndroidRuntime(14859): FATAL EXCEPTION: Thread-7971
09-11 16:57:07.119: E/AndroidRuntime(14859): java.lang.OutOfMemoryError
09-11 16:57:07.119: E/AndroidRuntime(14859):     at java.io.ByteArrayOutputStream.toByteArray(ByteArrayOutputStream.java:122)
09-11 16:57:07.119: E/AndroidRuntime(14859):    at com.android.volley.toolbox.BasicNetwork.entityToBytes(BasicNetwork.java:215)
09-11 16:57:07.119: E/AndroidRuntime(14859):    at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:104)
09-11 16:57:07.119: E/AndroidRuntime(14859):    at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)
@sjudd
Copy link
Collaborator

sjudd commented Sep 12, 2013

I haven't had any luck reproducing this. Are you able to do so reliably? If so, can you attach a heap dump (available from the debug panel in eclipse, or the monitor command line tool) from when you start seeing out of memory errors but before the application crashes? Any description of what you're doing when the oom error occurs would also be helpful (ie changing activities, scrolling a list of images etc).

@sjudd
Copy link
Collaborator

sjudd commented Sep 18, 2013

Since I haven't heard from you and I can't reproduce the issue, I'm going to close this for now.

If you get the chance to get back to me please do reopen the ticket.

@sjudd sjudd closed this as completed Sep 18, 2013
@lalith-b
Copy link
Author

I`m scrolling a listview containing 3-4 images on each listview cell. When I keep scrolling it caches the images on disc. When I reset the adapter by clearing data in the adapter and downloading it again. It will load it from cache, but as I keep scrolling the app crashes with OOM.

@sjudd sjudd reopened this Sep 25, 2013
@sjudd
Copy link
Collaborator

sjudd commented Sep 25, 2013

That sounds totally plausible, though I can't seem to reproduce it.

Is there any way you could provide me with a heap dump? You can can one from DDMS in eclipse, or using the 'monitor' commandline tool. Here's a blog post explaining some of the process: http://android-developers.blogspot.com/2011/03/memory-analysis-for-android.html

All I would really need is the file, you don't need to run hprof-conv either. If you can provide a heap dump, try to acquire it after reseting your adapter once or twice, but before you get an OOM.

Also please feel free to email me the heap dump if you'd prefer not to post it, or if you have any specific questions. My contact info is in the readme.

@lalith-b
Copy link
Author

I will mail you the heapdump once I get the OOM again.

@sjudd
Copy link
Collaborator

sjudd commented Sep 26, 2013

If you can reliably get the OOM exception to occur, it's best to get the heap dump just before it does. For example if scrolling up and down four times causes the exception, scroll up and down 3 times and then get the heap dump. The goal is to have some objects be leaked but not enough to cause an exception. If you acquire the heap dump just after the exception, I won't see the leak.

Thanks for your help with this.

@lalith-b
Copy link
Author

allright. This occurs generally after loading several 100's of images, and reproducing it might be a bit of a trouble. I will try to get the dump ASAP.

@sjudd
Copy link
Collaborator

sjudd commented Oct 20, 2013

@deathlord87 Are you still seeing this? Any updates?

@lalith-b
Copy link
Author

lalith-b commented Nov 4, 2013

yes,I get the error through crashlytics error/crash reporting tool. Please check

Fatal Exception java.lang.OutOfMemoryError
bitmap size exceeds VM budget(Heap Size=21959KB, Allocated=17949KB, Bitmap Size=10870KB)
0      BitmapFactory.java line
android.graphics.BitmapFactory.nativeDecodeStream
1      BitmapFactory.java line 690
android.graphics.BitmapFactory.decodeStream
2   Downsampler.java line 185
com.bumptech.glide.resize.load.Downsampler.decodeStream
3   Downsampler.java line 114
com.bumptech.glide.resize.load.Downsampler.downsampleWithSize
4   ImageManager.java line 78
com.bumptech.glide.resize.ImageManager$1.downsample
5   ImageResizer.java line 113
com.bumptech.glide.resize.load.ImageResizer.load
6   ImageResizer.java line 101
com.bumptech.glide.resize.load.ImageResizer.load
7   ImageManager.java line 527
com.bumptech.glide.resize.ImageManager$ImageManagerRunner.getFromDiskCache
8   ImageManager.java line 510 com.bumptech.glide.resize.ImageManager$ImageManagerRunner.run
9 ...   Handler.java line 587 android.os.Handler.handleCallback
12  HandlerThread.java line 60 android.os.HandlerThread.run

@sjudd
Copy link
Collaborator

sjudd commented Nov 4, 2013

So thats a 10mb image, which might be the issue. What options are you using to load the image? Can you paste your Glide.load() line?

@lalith-b
Copy link
Author

I think there's a leak with LruBitmapPool, I've seen large memories with LRUBitmapPool being like 20-30% of the whole app. I think the pool is never getting released.! is there any release logic assosiated with the LRUBitmapPool ?

@sjudd
Copy link
Collaborator

sjudd commented Nov 22, 2013

There is definitely release logic, but it's totally possible that it's got a bug. I'm planning on writing some unit tests for it, but if you want to try it, you may be able to uncover something sooner. It shouldn't be too hard to pattern them on the code for the lru memory cache.

@sjudd
Copy link
Collaborator

sjudd commented Nov 24, 2013

Added a clear memory method here: 6244968

Feel free to open a new issue if you think there might be a memory leak.

@sjudd sjudd closed this as completed Nov 24, 2013
@sjudd sjudd reopened this Nov 24, 2013
@sjudd
Copy link
Collaborator

sjudd commented Nov 24, 2013

Wups wrong bug!

@lalith-b
Copy link
Author

lalith-b commented Dec 3, 2013

Now after adding the new jar by compiling from source-master I get the below error.

FATAL EXCEPTION
java.lang.OutOfMemoryError
       at com.android.volley.toolbox.ByteArrayPool.getBuf(ByteArrayPool.java:101)
       at com.android.volley.toolbox.PoolingByteArrayOutputStream.<init>(PoolingByteArrayOutputStream.java:53)
       at com.android.volley.toolbox.BasicNetwork.entityToBytes(BasicNetwork.java:211)
       at com.android.volley.toolbox.BasicNetwork.performRequest(BasicNetwork.java:106)
       at com.android.volley.NetworkDispatcher.run(NetworkDispatcher.java:105)

@lalith-b
Copy link
Author

lalith-b commented Dec 5, 2013

Out of memory at

Thread-1197
       at com.bumptech.glide.resize.load.Downsampler.getDimensions(Downsampler.java:196)
       at com.bumptech.glide.resize.load.Downsampler.downsample(Downsampler.java:92)
       at com.bumptech.glide.resize.load.ImageResizer.load(ImageResizer.java:113)
       at com.bumptech.glide.resize.ImageManager$ImageManagerRunner.resizeIfNotFound(ImageManager.java:606)
       at com.bumptech.glide.resize.ImageManager$ImageManagerRunner.access$4(ImageManager.java:605)
       at com.bumptech.glide.resize.ImageManager$ImageManagerRunner$1$1$1.run(ImageManager.java:587)
       at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:422)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
       at java.lang.Thread.run(Thread.java:841)

@sjudd
Copy link
Collaborator

sjudd commented Dec 5, 2013

The exact exception is more or less irrelevant, all it indicates is that you have a memory leak in your app somewhere. Bitmap or byte array allocation are larger than average and tend to be the allocations that push your app over the edge.

There may or may not be a memory leak in Glide, but given the lack of reports from other users, I'd guess it's actually elsewhere in your app. Regardless I can't do much without a test app that demonstrates the problem, a heap dump, or at least some sample code...

@lalith-b
Copy link
Author

lalith-b commented Dec 9, 2013

I will email you the heap dump/hprof, once the OOM crash is produced. Add me - [email protected]

The glide code which produced the crash is below

Glide.load(imageurl.get(position))
.fitCenter()
.into(new DownloadImageTarget(holder,position))
.with(context);

also the DownloadImageTarget class -

private class DownloadImageTarget extends ImageViewTarget{
    private ViewHolder holder;

    /**
      * Instantiates a new download image target.
      *
      * @param holderFromAdapter the holder from adapter
      * @param position the position
      */
      public DownloadImageTarget(ViewHolder holderFromAdapter,int position) {
        super(holderFromAdapter.image);
        holder = holderFromAdapter;
      }

    /* (non-Javadoc)
     * @see com.bumptech.glide.presenter.target.ImageViewTarget#onImageReady(android.graphics.Bitmap)
     */
    @Override
    public void onImageReady(Bitmap arg0) {
        Log.e(TAG, "imageReady");
        // Size of image greater than 100kb, image width and image height 100px

        if (arg0!=null && arg0.getHeight() > 100 && arg0.getWidth() > 100) {
            holder.progressSpinner.setVisibility(View.INVISIBLE);
            holder.image.setImageBitmap(arg0);
            holder.imageTitle.setText(arg0.getWidth()+"x"+arg0.getHeight()+"px");
        }else{
        }
    }
}

Also it consistently crashes when loading a file from resource which takes as a full view background image on tablets (7inch and 10inch) although the same image is loaded on smaller screen sizes doesn`t cause any problem as yet. I've attached the image as well.

To produce the OOM for the below image I use the code :
bgImageView is match_parent/match_parent (so the whole screen will be used to load this image)

Glide.load(R.drawable.background).into(bgImageView);

tablet_onboarding_bg

@noorulhaq
Copy link

Hi,

I am also getting same out of memory issue in my android app and I am using Volley for network communication. While searching for the issue I stumble upon Glid. Since Glid is also using Volley at backend so I would like to share my experiance with Volley so far.

I am using volley NetworkImageViewer to load the images. While i was testing my app I noticed that some of the images were not loading at all and for those images I was getting out of memory error. To rectify the problem I looked into ImageRequest class source code there I found that parseNetworkResponse has code written to efficiently load bitmap image based on maxWidth and maxHeight BUT it is never getting called because both max bounds are always zero. After changing the code partially resolved the issue but still I am getting OOM error sometime.

The error comes on the method call decodeToByteArray. I hope whatever I have written makes sence as it is my first android app.

@lalith-b
Copy link
Author

There may be evident leaks in the android app(retained context,retained objects,leaky interfaces etc) which may cause OOM. However the major consumer/retained heap stayes with the Glide library's LRUBitmapBool class. If I switch to the Square's Picasso library it seem to handle the OOM.

@sjudd
Copy link
Collaborator

sjudd commented Dec 22, 2013

@deathlord87 I don't see anything that would cause a leak in your code. You could make it a bit more efficient by holding on to your target class in your viewholder rather than creating a new one in each call to Glide.load, but that's not a big deal.

As the for the OOM with that large image, it's a problem I'd like to look in to. I'd guess it's because can only downsample in discrete quantities so the right combination of memory limit, screen size, and image dimensions could cause an overly large bitmap to be allocated. I'd suspect you can fix this by loading the same image and using:

Glide.load(R.drawable.background).downsample(Downsampler.AT_MOST).into(bgImageView);

Can you provide the screen size in pixels of the tablets that cause the exception?

@noorulhaq Glide actually just uses volley to perform network operations, it doesn't use any of Volley's image loading code. Interesting find though, you might try to get in contact with the people who wrote volley to see if maxWidth and maxHeight being 0 is a bug in Volley's image loading code.

@noorulhaq
Copy link

Ok, if Glide is not using Volley for any image loading/scaling activities. Then how Glide ensures that what would be correct maximum image size (depending on device specifications) for a larger image to be loaded without any kind of crash.

Thanks,
Noor

@sjudd
Copy link
Collaborator

sjudd commented Dec 22, 2013

@noorulhaq Glide tries to intelligently use downsampling based on the size of an image and the size of the view the image will be displayed in to avoid crashes when loading larger images. I haven't looked at Volley's code recently but from what I remember it's basically the same idea.

@lalith-b
Copy link
Author

@sjudd the device that caused the OOM is a 7" Nexus tablet and a Samsung GTP7500 10" tab

@lalith-b
Copy link
Author

@sjudd there are a lot more crashes on Android 2.3-2.3.7 devices and its raining crashes of Downsampler/ByteArrayPool (volley)/ByteArrayOutputStream crash as OOM.

@sjudd
Copy link
Collaborator

sjudd commented Mar 20, 2014

@deathlord87 As we discussed over email, I think there's a memory leak in your app, and Glide is just the canary in the coalmine. You could verify that by just disabling Glide and allocating a single large (1024x1024) bitmap in onCreate of your activities and switching back and forth between screens. I'd imagine after a few screen changes you will still see an issue.

@lalith-b
Copy link
Author

@sjudd I will investigate this further, Although I tried with picasso image loading library and I'm facing some issues too. So probably the issues is due to leaks internally on my app. I shall share heapdumps through email, for clarification. Thanks for the patience.

@lalith-b
Copy link
Author

lalith-b commented Apr 1, 2014

also after digging into the Picasso source code I found this piece of code which might be useful for adding for cache implementation.

@TargetApi(11)
public static int getSafeMemoryCacheSize(Context context){
     ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
     boolean largeHeap = (context.getApplicationInfo().flags & android.content.pm.ApplicationInfo.FLAG_LARGE_HEAP) != 0;
     int memoryClass = am.getMemoryClass();
     if (largeHeap && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
          memoryClass = am.getLargeMemoryClass();
     }
     return (int) (1024 * 1024 * memoryClass * MEMORY_SIZE_RATIO);
}

The old implementation just checks the memoryclass and doesn't check if large heap is set on the manifest. Adding the above code will help apps with large heaps to utilize glide to the optimum.

@sjudd
Copy link
Collaborator

sjudd commented Jun 28, 2014

The 3.0a branch has an updated memory calculator based on screen size and also as categories so you can do Glide.get(context).setMemoryCategory() to dynamically adjust the the amount of memory Glide will use.

Since I haven't heard much re: the OOM exceptions, I'm going to close this for now. Feel free to reopen if you're still experiencing issues!

@sjudd sjudd closed this as completed Jun 28, 2014
@lalith-b
Copy link
Author

My application uses/downloads full hd images to display on screen which was an overhead for both memory and time for download, I solved it by using GraphicMagic on the server end to resize the images to fit aspect ratio based sizes of 4xx X 4xx to solve this.

Thanks for all the support and help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants