Android Low memory on start - android

For several apps that I have tested, it seems that the Heap memory usage is quite high even at the start of the application. For example, I have an app that is supposed to show an image from assets on an ImageView. But, even before loading the image, used Heap, is about 95%. When I load and display the image, it still fine, it increases used memory to about 98%. But, if I create a copy of the bitmap, then app crashes with out of memory error.
Again, my main question is why the amount of free memory is so low right at the start of an application, before any processing is done.

The reason you are seeing such high amount of memory usage percentage is because the heap hasn't grown to its maximum size. This means that even though you see 98% of usage that refers to your current heap size and not the total amount that you can use.
At runtime, the heap grows dynamically as Dalvik VM needs more memory. It is common that you start with a relatively small heap and with each GC if needed Dalvik will request more memory.
Now for your OutOfMemoryError it can be a lot of things. I would suggest sampling your bitmap at runtime using the BitmapFactory class inSampleSize

Related

How to know app going to reach max heap memory?

I am making Image gallery app with various types of image in term of resolution and size.
As per my observation, when app try to load large image its throws OutOfMemory.
How can i prevent app from OutofMemory?
Is there any way to get notification before app get crash because of OutOfMemory?
How can i know app going to reach heap capacity?
How can i prevent app from OutofMemory?
Allocate less memory. For example, with images, use things like inSampleSize on BitmapFactory.Options to only load into memory what you need, not the whole image.
Also, if your images will be the same resolution, use inBitmap to reuse already-allocated Bitmap objects, rather than let them get garbage-collected.
Is there any way to get notification before app get crash because of OutOfMemory?
No, because you are not out of memory.
How can i know app going to reach heap capacity?
You are not reaching "heap capacity".
Dalvik's garbage collector is a non-compacting (or non-moving) garbage collector, and so over time your heap becomes fragmented. OutOfMemoryError means that you are trying to allocate something for which there is no single free block big enough. I wrote a blog post that explains this a bit more and explains how the new ART runtime will help in this regard in the future.
getMemoryClass() gives you an estimation of how much memory you have available in your application.
getLargeMemoryClass() gives you an estimation of the large heap size you can allocate to your application.
So debug your application first to know where does it throw an exception exactly (line) then add logs to see how much memory you got.

Load large picture from file and add watermark

I am trying to find an efficient way to load a Bitmap from a file containing an arbitrarily large image, place a watermark (a logo) over it, and save it back to file.
I am aware of the memory problems that come with dealing with a large bitmap on Android. I don't want to load a smaller sample of the image, because I need to keep the same quality when saving it back to file.
Any help is appreciated.
Using BitmapFactory.decodeFile(File) leads to OutOfMemory issues when decoding large pictures
OutOfMemoryError occurs because there is no single block of heap space big enough for your request. The Dalvik garbage collector is a non-compacting collector, and so the heap will get fragmented into lots of smaller blocks of memory.
If all of the pictures will be the same resolution, and your minSdkVersion is 11 or higher, then allocate the Bitmap for it when your process starts up (e.g., in onCreate() of a custom Application class), and use that with inBitmap on your BitmapFactory.Options. Your attempt to allocate the Bitmap should succeed early on, before your heap gets fragmented, if the image can fit in the heap in the first place.
If they will not all be the same resolution, but you know the maximum resolution, and your minSdkVersion is 19 or higher, then do the same thing as I describe above. Android 4.4 extended inBitmap to support a Bitmap that is the same size or bigger than the image you are loading, whereas before it had to match the size exactly.
If none of that is possible:
Use android:largeHeap="true" to get a larger heap on API Level 11+ devices, or
Move your image-processing logic to the NDK, as native memory allocations do not count against the Dalvik heap limit, or
Move your image-processing logic to a dedicated short-lived process, so you get a clean separate heap at the point in time when you need to process a particular image
Those latter three options have costs to the user in terms of the system RAM consumption of your app and other effects.

Maximum Heap size for Nexus?

I am using Galaxy Nexus(i9250) for development and testing. I noticed strange fact- sometimes when the total heap size is 64mb and allocated heap size is in and around 56-60mb, app crashes. But sometimes I noticed that even the memory shoots up to 80mb, app didn't crashes.
Initially I thought that maximum heap size for devices of the range nexus will be 64mb(now I realize it is wrong). So my question is what is the maximum heap size a device can use. If it is variable based on device, then on what factor heap size depends. I knew this is a common question. Could anyone guide me to the right answer. Thanks in advance!
NOTE: I didn't use LargeHeapSize = true; in my code
Considering , your app crashes every time giving "OutOfMemoryError"
DVM starts by allocating a small heap, after every garbage collection cycle it checks for free heap and compares it to the total heap memory and adds more memory in case that the difference is too small. So Heap can be increased or decreased at runtime as per Dalvik VM's requirement by OS.
So, when their is enough memory available in the system your app didn't get crashed when the memory shoots up to 80mb.(Assuming 64MB is not the hard limit of heap size)
Yes there is a hard limit on the heap size of every device which can be increased by using "LargeHeapSize = true" , but this might be too costly in terms of app performance as increased heap size is directly proportional to the time taken by the garbage collection process(as GC now have to traverse more objects inside bigger heap). So it is a big "NO,NO" until unless you exactly know what and why are you going for larger heap size.
on what factor heap size depends:
Heap size mainly depends on the resolution of the device you are
using, as more resolution needs larger images/bitmaps size to fit
in.(more pixels = needs more memory to incorporate)
Although, I didn't got through any written proof of this.. As per my
understanding Heap size also depends on the RAM size. Since, bigger
RAM size will allow more flexibility of multitasking and lesser
chances of getting the "OutOfMemoryError"
In case you needs to know exact amount of heap memory you can use, ActivityManager.getMemoryClass(). This method returns an integer indicating the number of megabytes available for your app's heap
ActivityManager.getLargeMemoryClass() for larger heap size
it is not clear that what device you are exactly talking about. It is also not clear how you calculated your heap memory.
I recommend you calculate your heap memory and available memory using this link
But if your app uses Native Memory, their are no restriction on that link.
I would only use the DDMS values as a guide to find memory leaks and memory allocation problems rather than some specific number given that you can target. Any Android application will be expected to run on a variety of devices so while you may have tuned your app for a 'Galaxy Nexus' you will want to be able to run on older devices, and test appropriately. See
#dongshengcn comment.
In addition to the links by #minhaz I would also read: Understanding Heap Size.
If you are trying to get a better understanding of memory management on Android then you should read Android Framework Engineer #hackbod's answer to: How to Discover Memory Usage of My Application in Android.

how to set heap size to minimum when application was closed

I am developing one android application which is using more images with resolution 640*960 approximately. all these images are loaded with bitmaps with proper scaling factor.
When i am loading bitmpas heap size is increasing and it is not decreasing even though i am recycling the bitmpas. as i read few theory's regarding this issue maximum says once heap increased it will not decreased at all.
My problem is if i close my application when heap size is 10MB , and when i reopen the application heap is starts from 10Mb. it causes VM exceeds Maximum heap memory and then Out Of Memory after some time.
what i have to do for this, and i am guarantee that my application will never close with out recycling bitmaps.
can any one please suggest me how to minimze the heap memory and solve this OOM.
Even i faced the same problem....you can refer this link for effectively loading the bitmaps http://developer.android.com/training/displaying-bitmaps/load-bitmap.html
Once heap size has exceeded the limit your garbage collector runs...and it cleans up any unwanted object.so its better not to call garbage collector as it will run automatically.
Applications running on API Level 11+ can have android:largeHeap="true" on the element in the manifest to request a larger-than-normal heap size
In your onCreate method in your activity you can use this(i did'nt try this)
dalvik.system.VMRuntime.getRuntime().setMinimumHeapSize(yournumberhere);

BitmapFactory OOM driving me nuts

I've been doing a lot of searching and I know a lot of other people
are experiencing the same OOM memory problems with BitmapFactory. My
app only shows a total memory available of 4MB using Runtime.getRuntime
().totalMemory(). If the limit is 16MB, then why doesn't the total
memory grow to make room for the bitmap? Instead it throws an error.
I also don't understand that if I have 1.6MB of free memory according
to Runtime.getRuntime().freeMemory() why do I get an error saying "VM
won't let us allocate 614400 bytes"? Seems to me I have plenty
available memory.
My app is complete except for this problem, which goes away when I
reboot the phone so that my app is the only thing running. I'm using
an HTC Hero for device testing (Android 1.5).
At this point I'm thinking the only way around this is to somehow
avoid using BitmapFactory.
Anyone have any ideas on this or an explanation as to why VM won't
allocate 614KB when there's 1.6MB of free memory?
[Note that (as CommonsWare points out below) the whole approach in this answer only applies up to and including 2.3.x (Gingerbread). As of Honeycomb Bitmap data is allocated in the VM heap.]
Bitmap data is not allocated in the VM heap. There is a reference to it in the VM heap (which is small), but the actual data is allocated in the Native heap by the underlying Skia graphics library.
Unfortunately, while the definition of BitmapFactory.decode...() says that it returns null if the image data could not be decoded, the Skia implementation (or rather the JNI glue between the Java code and Skia) logs the message you’re seeing ("VM won't let us allocate xxxx bytes") and then throws an OutOfMemory exception with the misleading message "bitmap size exceeds VM budget".
The issue is not in the VM heap but is rather in the Native heap. The Natïve heap is shared between running applications, so the amount of free space depends on what other applications are running and their bitmap usage. But, given that BitmapFactory will not return, you need a way to figure out if the call is going to succeed before you make it.
There are routines to monitor the size of the Native heap (see the Debug class getNative methods). However, I have found that getNativeHeapFreeSize() and getNativeHeapSize() are not reliable. So in one of my applications that dynamically creates a large number of bitmaps I do the following.
The Native heap size varies by platform. So at startup, we check the maximum allowed VM heap size to determine the maximum allowed Native heap size. [The magic numbers were determined by testing on 2.1 and 2.2, and may be different on other API levels.]
long mMaxVmHeap = Runtime.getRuntime().maxMemory()/1024;
long mMaxNativeHeap = 16*1024;
if (mMaxVmHeap == 16*1024)
mMaxNativeHeap = 16*1024;
else if (mMaxVmHeap == 24*1024)
mMaxNativeHeap = 24*1024;
else
Log.w(TAG, "Unrecognized VM heap size = " + mMaxVmHeap);
Then each time we need to call BitmapFactory we precede the call by a check of the form.
long sizeReqd = bitmapWidth * bitmapHeight * targetBpp / 8;
long allocNativeHeap = Debug.getNativeHeapAllocatedSize();
if ((sizeReqd + allocNativeHeap + heapPad) >= mMaxNativeHeap)
{
// Do not call BitmapFactory…
}
Note that the heapPad is a magic number to allow for the fact that a) the reporting of Native heap size is "soft" and b) we want to leave some space in the Native heap for other applications. We are running with a 3*1024*1024 (ie 3Mbytes) pad currently.
1.6 MB of memory seems like a lot but it could be the case that the memory is so badly fragmented that it can't allocate such big block of memory in one go (still this does sound very strange).
One common cause of OOM while using image resources is when one is decompressing JPG, PNG, GIF images with really high resolutions. You need to bear in mind that all these formats are pretty well compressed and take up very little space but once you load the images to the phone, the memory they're going to use is something like width * height * 4 bytes. Also, when decompression kicks in, a few other auxiliary data structures need to be loaded for the decoding step.
It seems like the issues given in Torid's answer have been resolved in the more recent versions of Android.
However, if you are using an image cache (a specialized one or even just a regular HashMap), it is pretty easy to get this error by creating a memory leak.
In my experience, if you inadvertently hold on to your Bitmap references and create a memory leak, OP's error (an referring to the BitmapFactory and native methods) is the one that will crash your app (up to ICS - 14 and +?)
To avoid this, make your you "let go" of your Bitmaps. This means using SoftReferences in the final tier of your cache, so that Bitmaps can get garbage collected out of it. This should work, but if you are still getting crashes, you can try to explicitly mark certain Bitmaps for collection by using bitmap.recycle(), just remember to never return a bitmap for use in your app if bitmap.isRecycled().
As an aside, LinkedHashMaps are a great tool for easily implementing pretty good cache structures, especially if you combine hard and soft references like in this example (starting line 308)... but using hard references is also how you can get yourself into memory leak situations if you mess up.
Although usually it doesnt make sense to catch an Error because usually they are thrown only by the vm but in this particular case the Error is thrown by the jni glue code thus it is very simple to handle cases where you could not load the image: just catch the OutOfMemoryError.
Although this is a fairly high level answer, the problem for me turned out to be using hardware acceleration on all of my views. Most of my views have custom Bitmap manipulation, which I figured to be the source of the large native heap size, but in fact when disabling hardware acceleration the native heap usage was cut down by a factor of 4.
It seems as though hardware acceleration will do all kinds of caching on your views, creating bitmaps of its own, and since all bitmaps share the native heap, the allocation size can grow pretty dramatically.

Categories

Resources