Android heap size and SoftReferences - android

I have an application which creates a series of Bitmaps. I am holding these Bitmaps in SoftReferences, to avoid running out of memory. I would like the heap size to grow to the maximum 16MBs before it starts collecting my SoftReferences. However, the SoftReferences are collected very eagerly, prior to growing the heap to it's max. Is there anyway to force the references to be collected less eagerly? or to manually grow the heap to the max? Possibly a way to just start the application with 16mb allocated?

There is currently no way to modify the SoftReference collection behavior.
I'm not sure what you mean by "manually growing the heap to the max".
If these are instances of the Bitmap class (as opposed to some custom bitmap implementation), the pixel data is actually stored on the native heap, but uses an annoying "external allocation" accounting trick, which complicates the situation further. (Notably, the storage is freed by a finalizer, not the GC, and finalizers have to execute in a separate thread after the GC completes. It's possible to allocate Bitmaps until you run out of memory, and the GC has no way to release the memory before throwing an OOM error.)

It's a known issue in Andriod. When VM collects soft references, it either collects all or none, although it should collect 'some' and should not collect anything when there is plenty of free heap.
Check: http://code-gotcha.blogspot.com/2011/09/softreference.html

Related

Android - limit heap size to 16MB for testing purposes?

I have created an Android app and I now want to make sure that it never goes above 16MB of heap usage.
Unfortunately for this task my device has a much bigger heap than the minimum of 16MB, it has at least 32MB.
When I track the allocations it just keeps allocating and allocating and seldom garbage collects which makes it hard to track down memory leaks.
I have tried to use various profilers but it is not easy.
Preferrably I would like to back and forth between activities and just see the heap go up and then back down so that there are no memory leaks but since the garbage collection is postponed until it is really needed this seems hard to do.
Is it possible to limit the heap size to 16MB on a 32MB heap size device for testing purposes?
The best way to do this is to use an Android Virtual Device, as you can configure the heap size in the Android emulator. It is in the advanced options when creating an AVD.
However if you must test this on a real device you can simulate having a smaller heap by creating a memory leak of heap memory on startup. Make sure you keep a strong reference to the object you allocate so it isn't garbage collected.
On a device with 32MB heap size, if you create a 16MB leak on startup this will leave the remaining 16MB of heap space for your application to use.

Understanding Android garbage collection

I'm having trouble finding good information about garbage collection in Android.
I don't really understand when you have a memory exception
Here's a question:
When I run my application and monitor it with the Android Device Monitor
I see that the allocated memory is 8 MB when the application has just started.
There's a button that creates an object each time it's pushed.
So when i keep pushing the button, the allocated memory grows until
it reaches the heap size. When the heap size is reached, the allocated
memory goes back to 8 MB but the heap has grown a little bit. After that,
this whole thing happens again and the heap keeps growing
Do i have a memory exception in this case? or is it normal that
the heap size keeps growing?
The heap size is sort of reserved memory you can use. The allocated memory is the actual memory in use.
When the allocated memory is nearing the heap size, and you see the allocated memory drop, objects are being garbage collected. The heap size will grow a bit, since you probably need more memory than currently reserved.
In the end, if you keep allocating memory without releasing it, the heap size and allocated memory will grow, until the system runs out of memory (for your application). At that point, an OutOfMemoryException will be thrown, and your app will crash.
Read Managing Your App's Memory | Android Developers for a deeper insight.

Android Dalvik VM Logcat

Can anyone explain the below Logcat message :
D/dalvikvm(4440): GC_EXTERNAL_ALLOC freed 338K, 47% free 6427K/11911K, external 20418K/22446K, paused 53ms
E/dalvikvm-heap(4440): 2519424-byte external allocation too large for this process.
D/dalvikvm(4440): GC_FOR_MALLOC freed <1K, 47% free 6427K/11911K, external 20398K/22446K, paused 40ms
E/GraphicsJNI(4440): VM won't let us allocate 2519424 bytes
In older versions of Android, certain bits of native framework code would tell the VM about native allocations. This "external allocation" mechanism was an ugly hack introduced so that native allocations would cause the Dalvik VM to do a garbage collection pass.
The basic problem was that the Java-language Bitmap object used native memory for the pixel storage. Because the managed-heap objects were tiny, and the native-heap objects were large, you could allocate tons of Bitmaps without causing a GC. This was causing apps to bloat up and the system to slow down.
So, "external allocations" were introduced. Whenever the pixel storage for a Bitmap was allocated on the native heap, an equal amount of memory was deducted from the managed heap. The idea is that, if your heap is filling up with no-longer-reference bitmaps, you'll run out of managed heap space and the GC will fire.
(Unfortunately the GC can't actually release the native storage -- you need to run a finalizer to do that, and finalizers run in a separate pass after the GC completes. For a while the native objects were also holding on to some additional managed-heap objects, so you'd have to GC + finalize + GC to actually clean everything up.)
My "favorite" part about external allocations is that the API was a simple "increase by N" / "decrease by N", which meant there was no way to associate the native heap with a managed heap object, or check for leaks. Because all of the information about the Bitmap was kept in the native object, you couldn't even guess at how much native storage was needed, so it was impossible to look at an hprof dump and figure out how much memory a Bitmap was actually using.
In Android 3.0 ("Honeycomb") the pixel storage was moved onto the managed heap, and the external allocation mechanism was removed.
So, what the log message in your question means is: some code, probably Bitmap, wanted to allocate 2.5MB of native heap, but that would exceed the VM's external allocation heap limit. You need to figure out what's eating up 20MB of external allocation storage and release some of it.
The only way to get information about external allocations is by watching the event log. A few years back I threw a script together (gclog.py -- was in AOSP dalvik/tools for a while). I have no idea if it will still do anything useful. I talk about how to use it in this old thread.

Getting amount of free memory and total available memory

I have an application which is performing some memory intensive tasks. I am trying to figure out what the total available memory is and what the available free memory is. I am doing so by using Runtime.getRuntime().freeMemory() and Runtime.getRuntime().totalMemory()
I am curious if the result I am getting is the total amount of free memory and total memory on the device or if it is the total amount of memory available to that instance of the Dalvik VM that the application is running on top of? I would appreciate some feedback. Thanks!
According to the JavaDocs, those should be in terms of the heap for your process. That being said:
getMemoryClass() on ActivityManager is a more Android-y way to determine the heap size for your process.
Because Dalvik's garbage collector is non-compacting, memory reported by methods like freeMemory() will overstate how much you can allocate. By "non-compacting", I mean that if you free up two blocks of memory that happen to be adjacent, the garbage collector leaves them as two blocks of memory. Contrast this to the Java VM, which will recognize that the two blocks are adjacent and update the heap to reflect one larger free block rather than two smaller free blocks. The non-compacting garbage collector means that your heap is more prone to fragmentation than complete exhaustion. You will try to allocate some large block and get an OutOfMemoryError, not because the heap lacks free memory, but because there is no single free block big enough for your request.

what shoud be difference between "NativeHeapAllocatedSize" and "Runtime totalMemory" in Android to prevent from "OutOfmemory Exception"?

hello i m doing some runtime calculation for getting NativeHeap memory and allocated memory at runtime, so any one can suggest me
what should be the difference between "Debug.getNativeHeapAllocatedSize()" and "Runtime.getRuntime().totalMemory()"
so can prevent app by OutOf Memory Exception.
Thanks
Runtime.getRuntime().totalMemory()
Returns the total amount of memory which is available to the running program.
getNativeHeapAllocatedSize()
For devices below HoneyComb most of the huge allocations are deferred to the native heap (e.g Bitmaps). Hence this api is useful to find out how much of native heap is allocated.
OOM Errors occurs when there are no objects which can be freed by the DVM. Typically you have about 16MB in the Heap to play with (for a standard phone). Check your logs* to see GC statements having info about how much of memory is allocated.
I don't think there should be a fixed ratio to cause an OOM error. Like in the case when you load a very huge bitmap, here the native memory used is huge.
Slide 25

Categories

Resources