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?
Most devices running Android 2.3 or later will return this size as 24MB or higher but is limited to 36 MB (depending on the specific device configuration). If your app hits this heap limit and tries to allocate more memory, it will receive an OutOfMemoryError and will terminate. Heap memory is used to allocate objects.
By default, Android Studio has a maximum heap size of 1280MB. If you are working on a large project, or your system has a lot of RAM, you can improve performance by increasing the maximum heap size for Android Studio processes, such as the core IDE, Gradle daemon, and Kotlin daemon.
The heap size value is determined by the amount of memory available in the computer. Initial heap size is 1/64th of the computer's physical memory or reasonable minimum based on platform (whichever is larger) by default. The initial heap size can be overridden using -Xms.
It is recommended to increase the Java heap space only up to one-half of the total RAM available on the server. Increasing the Java heap space beyond that value can cause performance problems. For example, if your server has 16 GB of RAM available, then the maximum heap space you should use is 8 GB.
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. OutOfMemoryError
s 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).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With