Android Understanding Heap Sizes

30,861

Solution 1

When you set the VM budget on your emulator/device, what you are doing is telling the heap the maximum size it is allowed to be. At runtime, the heap grows dynamically in size as the Dalvik VM requests system memory from the operating system. The Dalvik VM typically starts by allocating a relatively small heap. Then after each GC run it checks to see how much free heap memory there is. If the ratio of free heap to total heap is too small, the Dalvik VM will then add more memory to the heap (up to the maximum configured heap size).

That being said, the reason why you are not seeing "24 mb" on your DDMS screen is because the heap hasn't grown to its maximum size. This allows Android to make good use of the already small amount of memory that is available on handheld devices.

As for why your application is crashing on the emulator and not your phone, that does seem odd (are you sure the numbers are correct?). You should keep in mind, however, that memory is managed dynamically and that total memory utilization is determined based on a number of external factors (the speed/frequency at which garbage collection is performed, etc.).

Finally, for the reasons I mentioned above, it would be difficult to say for sure how well your application manages memory based on the single line of information you provided above. We'd really need to see some of your code. OutOfMemoryErrors are definitely worth worrying about, however, so I'd definitely look into your application's memory usage. One thing you might consider is to sample your bitmap images at runtime with calls to inSampleSize using the BitmapFactory class. This can help reduce the amount of memory required to load your drawable bitmaps. Either that or you could reduce the resolution of your drawables (although 20 kb each sounds fine to me).

Solution 2

Even if your application doesn't reach the "24mb" (varies within devices) heap limit you might still have crashes because Android takes a while to grow the heap space for your app.

In my situation I was creating and dumping several images in a small amount of time.

Quite often I was getting OutOfMemoryError.

It seems Android wasn't fast enough to grow the heap space for my app.

I believe I solved this issue by using the largeHeap setting in the Manifest file. With that setting on, Android leaves more free memory every time it grows the heap, minimizing the chance of hitting the current limit.

I don't use the 24mb limit but this largeHeap conf was quite handy.

You just need to set largeHeap="true" on the application tag of your AndroidManifest.xml

<application
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:theme="@style/AppTheme" >

Still, make sure you are carefull when dealing with images, like @Alex Lockwood advised.

Share:
30,861
John P.
Author by

John P.

Hi, my name is John and I'm a Software Engineer.

Updated on October 22, 2021

Comments

  • John P.
    John P. over 2 years

    I'm fairly new to Android development and I can't seem to grasp the Java Out of Memory exception. I know it means that my app has gone over the VM budget but after Googling this many times I still don't seem to grasp this concept. I'm afraid that my app uses too much memory because I have six button selectors per screen with two bitmaps for each selector which are around 20 kb each according to the properties tab. On my rooted G2x I have set the VM budget to 12mb, restarted my phone and ran my app with no problems whatsoever. I am unbinding drawables on each onDestroy() and hinting at the GC to run here also. After using the app for a while in the emulator I click "Cause GC" on my DDMS screen and the results are ID=1, Heap Size 6.133 MB, Allocated 2.895MB, Free 3.238 MB, % Used 47.20, # Objects 52,623.

    This is where I don't understand what's happening, my emulator is set to 24MB of VM. Where is that number? The actual problem I'm having is that if I set the emulator to 16MB of VM my app crashes on the second activity with the Out of Memory exception. How come it doesn't crash on my phone with the VM set to 12 MB or on my old HTC Magic phone with 12 MB of VM stock? Also, is my app is taking up too much memory? I have no idea if those DDMS numbers are good or not.

    As for my code I have every image specified in XML layouts. I do not do anything programmatically with them except for adding listeners to them. I found this bit of code on here and I've added it to every activity that I have...

    @Override
    protected void onDestroy() {
        super.onDestroy();
    
        unbindDrawables(findViewById(R.id.myRootLayout));
        System.gc();
    }
    
    private void unbindDrawables(View view) {
        if (view.getBackground() != null) {
            view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup && !(view instanceof AdapterView)) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
                unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
            ((ViewGroup) view).removeAllViews();
        }
    }
    

    Otherwise all I do is add onClickListeners to the buttons that have the PNG backgrounds. I would like to learn how to specify button backgrounds programmatically but I need to have the selector functions like on focus, on press, non-focused but pressed etc. to make the button backgrounds change according to user interaction. I have reviewed the docs about this but it seems overwhelming, that's why I figured I'd start here with the basics of managing Heaps and work my way up to specifying selectors in code. This may not make sense but is there a "healthy" amount of memory allocation that an app could allocate without getting close to the Out of Memory exception? For example, if an app allocated 6MB it should be fine but 8MB would be pushing it, are there bounds like that in memory allocation?

  • John P.
    John P. almost 12 years
    Thank you very much! I learned a lot from that. I'm adding some info to the bottom of the question
  • Sanal Varghese
    Sanal Varghese about 11 years
    Use largeHeap="true" with atmost care. Because using this may adversly affect your app perfomance.Because you are telling system to increase the maximum heap limit. When this happens it will take more time for garbage collection. If you check the log you can see that GC Pause time will be greater. Ideally it should be between 2-5ms.In this case it can vary even upto 30-45ms. So don't set large heap property to true just because you are getting out of memory. Use it as the very last step.Otherwise it will be a perfomance hit.
  • tbraun
    tbraun about 11 years
    Indeed. In my case, I'm dealing with lots of high quality images dynamically and, before using the largeHeap option, I've implemented code to: - load images sampled - resize images to perfect fit - clearing unused images from memory - caching images in "disk" I was still having problems which were solved only with the largeHeap option. Still, use it only after trying everything else, like @SanalVarghese advised.
  • Mathijs Segers
    Mathijs Segers about 10 years
    Just adding to this, I've been having loads of issues with my app's memory it's size increases greatly. It might not be set together efficiently at this point but it should have been able to not-exeed the heep limit. However it wouldn't ever release many resources. For some reason it does it very well after applying the largeHeap option. Thanks a bunch.
  • ToolmakerSteve
    ToolmakerSteve about 7 years
    Re resolution comment "20 kb each sounds fine" - AFAIK, it doesn't matter what the file size is (that will be smaller for images that compress better), it matters what the DIMENSIONS are; in memory, for full color, will take 4B per pixel, right? Hence, it is important to resize the image when you load it [android docs - Load a Scaled Down Version into Memory], based on the actual needed size, for the current device.