xunice / libs-for-android

Automatically exported from code.google.com/p/libs-for-android
Apache License 2.0
0 stars 0 forks source link

OutOfMemory with big arrays #4

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?
1.Array with 200-400 images midle quality
2. Fast scrolling top/down
3. Crash with outOfMemory

What is the expected output? What do you see instead?
Crash outOfMemory exception

What version of the product are you using? On what operating system?
Latest

Please provide any additional information below.
It reproduce on slowly devices and emulators, If the user behaves like a monkey.

Original issue reported on code.google.com by istin2007 on 21 Mar 2011 at 11:16

GoogleCodeExporter commented 9 years ago
Are you using the pre-built imageloader.jar or did you build your own?

Original comment by pbald...@google.com on 21 Mar 2011 at 5:10

GoogleCodeExporter commented 9 years ago
I use the pre-built imageloader.jar.

Original comment by istin2007 on 21 Mar 2011 at 6:21

GoogleCodeExporter commented 9 years ago
Try building imageloader.jar from the latest source code and see if that helps. 
 There was a recent change that catches and handles erroneous OutOfMemoryErrors.

There is more info here:
http://code.google.com/p/libs-for-android/wiki/GettingStarted

Original comment by pbald...@google.com on 21 Mar 2011 at 6:58

GoogleCodeExporter commented 9 years ago
Thanks. Tomorrow I will try it.

Original comment by istin2007 on 21 Mar 2011 at 7:02

GoogleCodeExporter commented 9 years ago
Hi. I tried it with your latest source, and I still have this problem if user 
like monkey(quickly do somethings about 2-4 mins).

Original comment by istin2007 on 22 Mar 2011 at 9:36

GoogleCodeExporter commented 9 years ago
Hi, is there any progress on this. I'm seeing similar behaviour in a gallery 
when loading > 15 large images. I am paging through these and reusing the 
ImageView on each page so I would expect memory to be freed up when necessary 
however it eventually fails with the following logcat output:

07-04 11:13:17.337: ERROR/dalvikvm-heap(24081): 624960-byte external allocation 
too large for this process.

07-04 11:13:17.376: ERROR/GraphicsJNI(24081): VM won't let us allocate 624960 
bytes

07-04 11:13:17.505: ERROR/ImageLoader(24081): Failed to load 
http://static.guim.co.uk/sys-images/Guardian/Pix/pictures/2011/7/3/1309651678530
/World-Road-Race-Champion--003.jpg
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
        at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:470)
        at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:525)
        at com.google.android.imageloader.BitmapContentHandler.getContent(BitmapContentHandler.java:42)
        at com.google.android.imageloader.BitmapContentHandler.getContent(BitmapContentHandler.java:36)
        at com.google.android.filecache.FileResponseCache$FileResponseCacheContentHandler.getContent(FileResponseCache.java:546)
        at com.google.android.imageloader.ImageLoader$ImageRequest.loadImage(ImageLoader.java:751)
        at com.google.android.imageloader.ImageLoader$ImageRequest.execute(ImageLoader.java:792)
        at com.google.android.imageloader.ImageLoader$ImageTask.doInBackground(ImageLoader.java:986)
        at com.google.android.imageloader.ImageLoader$ImageTask.doInBackground(ImageLoader.java:946)
        at android.os.AsyncTask$2.call(AsyncTask.java:185)
        at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
        at java.util.concurrent.FutureTask.run(FutureTask.java:138)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
        at java.lang.Thread.run(Thread.java:1019)

Original comment by rupert.b...@guardian.co.uk on 4 Jul 2011 at 10:15

GoogleCodeExporter commented 9 years ago
I think this was actually down to setting the IMAGE_CACHE_SIZE incorrectly. I 
copy and pasted code from the Jamendo app as follows:
// 50% of available memory, up to a maximum of 32MB
private static final long IMAGE_CACHE_SIZE = 
Math.max(Runtime.getRuntime().maxMemory() / 2, 32 * 1024 * 1024);

But as detailed in this issue:
http://code.google.com/p/libs-for-android/issues/detail?id=11
it should be Math.min()

Original comment by rupert.b...@guardian.co.uk on 31 Aug 2011 at 3:54

GoogleCodeExporter commented 9 years ago
Actually, even after correcting the cache size I was still running into 
problems because removeEldestEntry() in BitmapCache will only remove one entry 
rather than continuing to remove them until the cache is back under size. This 
causes problems where there is a big difference between the smallest and 
largest images in your cache.

To get round this I changed the implementation of removeEldestEntry to the 
following, which will keep removing entries until the cache is back under size:

@Override
    protected boolean removeEldestEntry(Map.Entry<K, Bitmap> eldest) {
        // This will increase the runtime for insertion to O(n),
        // but it's less error-prone than maintaining a counter.
        // The maximum value of n should generally be small as long
        // as the images are not tiny and the max size is not huge.

        long currentSize = sizeOf(values());
        if (currentSize < mMaxSize) return false;
        android.util.Log.d("ImageLoader.BitmapCache", "Cache is oversize, removing eldest entry");

        currentSize -= sizeOf(eldest.getValue());
        remove(eldest.getKey());
        if (currentSize < mMaxSize) return false;

        android.util.Log.d("ImageLoader.BitmapCache", "Cache is still oversize finding more entries to remove");
        //The first entries in the entrySet collection will be the eldest so remove them first
        ArrayList<K> keysToRemove = new ArrayList<K>();
        for(Map.Entry<K, Bitmap> entry : entrySet()){
            keysToRemove.add(entry.getKey());
            currentSize -= sizeOf(entry.getValue());
            if (currentSize < mMaxSize) break;
        }

        android.util.Log.d("ImageLoader.BitmapCache", "Removing " + keysToRemove.size() + " from cache");
        //remove the entries
        for (K key : keysToRemove) {
            remove(key);
        }
        return false;
    }

Original comment by rupert.b...@guardian.co.uk on 1 Sep 2011 at 12:18

GoogleCodeExporter commented 9 years ago
https://code.google.com/p/libs-for-android/source/detail?r=0fac14602344a76544c88
ce8e7806c12b7b9a18e

Original comment by pbald...@google.com on 1 Sep 2011 at 5:07