what's the meaning of Free Memory for Android APP? - android

I have a problem. My App's memory is taken away by system when in background. So, I try to release some resource, like bitmap, to avoid this. But from the memory tool in Android Studio, I found that there are two kinds of data about memory. One is "Free" and the other is "Allocated". After recycling bitmap, the Allocated part get down while the Free part get higher. On other hand, I check the cellphone's setting->application management->running, it shows that my APP hold nearly the same memory as the one before I recycled bitmap and the memory usage just equal to the Free part+Allocated part.
I'm confused. Is the freed memory by recycling bitmap still occupied by my APP in view of system? If so, my app is still facing the risk of being killed. How can I save my APP in background?

Related

android:largeHeap="true" convention?

I'm writing an image gallery app and I keep running into out of memory errors. I cache all my images but the problem occurs when I try switching between images really fast. I'm assuming the app is allocating memory faster than the GC has time to free them up (because the crash doesn't happen when I switch images slowly).
After banging my head against this problem for days, I finally decided to give largeHeap setting in the manifest file a try. After this setting, my app no longer crashes no matter how fast I switch between images.
Now, I want to know if there is any convention or general guideline to using largeHeap setting because it probably wouldn't make much sense if, say, a note taking app used largeHeap. Generally speaking, what apps are a good candidate for largeHeap setting?
Thanks
Generally speaking, what apps are a good candidate for largeHeap setting?
Ones where you can justify to the user why you're forcing all their other apps out of memory, to give you an outsized amount of heap space.
Personally, I would not consider "an image gallery app" to qualify. AutoCAD, video editors, and the like would qualify.
With respect to your memory management issues, make sure that you are using inBitmap on BitmapOptions when running on API Level 11+, so you recycle existing buffers rather than go through garbage collection. Particularly for an image gallery, where you probably have a lot of fairly consistent thumbnail sizes, recycling existing buffers will be a huge benefit. This can help both overall memory consumption (i.e., you are truly out of memory) and memory fragmentation (i.e., you get an OutOfMemoryError with plenty of heap space, but no single block big enough for your allocation, due to Android's frakkin' non-compacting garbage collector).
You might also consider looking at existing image cache implementations, such as the one that Picasso has, to see if there are some tips you could learn (or possibly just reuse).
First, make sure you aren't loading larger bitmaps than necessary:
Load a Scaled Down Version into Memory.
Then, before trying largeHeap, try to free the memory quickly yourself:
If you call bitmap.recycle(); as soon as you are SURE you will not use a bitmap again, then the bulk of that bitmap's memory will be immediately freed. (When the GC gets around to it, all that remains is a tiny object.)
On newer Android versions, there are alternatives (instead of recycle) that may be more effective:
Managing Bitmap Memory
Personally, I still use recycle often, especially if I might be loading a different size image, so can't reuse the existing one. Also, I find it easier to code "unloading" of old media separately from "loading" of new media, when changing to a different fragment or activity:
As leave the old fragment, all old bitmaps I recycle (then, if reachable from a static field, set to null).
The rule of thumb for whether to use largeHeap, is to consider it after you've tried alternative ways to reduce memory usage.
Code your app so you could turn it off again, and still run.
For example, monitor your memory usage, and load "scaled down" bitmaps if memory is tight. Will the user really notice if a given image is not at their device's "retina" resolution?
Or if it is an older, slower, device, will largeHeap make your app feel unresponsive / jerky? If so, can you drop resolution even further, or show fewer bitmaps at one time?
Get your app to work in all circumstances, without largeHeap [by techniques mentioned above]. NOTE: you can "force-test" running on tight memory, by allocating some "dummy" bitmaps, and hold references to them in global fields, so they don't get freed.
NOW you are able to evaluate the trade-off, as it affects YOUR app:
When you do turn largeHeap on, use your app heavily - are there places where it is now "more sluggish", or animations "stutter" or otherwise seem less smooth? BE SURE TO TEST ON AT LEAST ONE OLDER DEVICE, AND ON ONE HIGH_RESOLUTION DEVICE.
You might be seeing long GC times, due to the larger heap.
OR you might conclude that largeHeap is working well for you, and now you can confidently say that it is the best choice in your circumstance.

How to implement an in Memory Image Cache in Android?

Until now I'm using a SoftReference Cache for images in Android. This cache is used for images that are shown in ListViews and should help holding images of items in memory that are not shown on the screen, if there is enough memory left.
The problem with this is that SoftReferences are garbage collected nearly at the very moment the last hard reference is released. The result of this is that an image that is removed from the screen is garbage collected at that moment and if the user scrolls back to this entry in the ListView the image is reloaded from the internal phone memory resulting in a complex lazy loading process, resulting in frequent redraws of the list and general bad performance.
The bug request for the soft reference behavior states that this is the intended behavior and that you should use a LRU-Cache for caching this kind of stuff.
Know to my question. The LRU cache will only take as much memory as I allow him to. But if the app needs a lot of memory it will not free memory. How should I determine how much memory I can allow the Cache to use, and is there a way to reduce the size of the cache if the memory situation of the phone becomes tight?
At the moment the image cache is saved inside the application as a kind of global image storage for all activities. This would result in my app constantly using all the memory of the image cache even if my activities are in the background or destroyed.
Keeping background processes alive is an OS-level optimization that makes switching back to your process fast. Your process will stay alive only as long as the OS can afford the memory; when that memory is needed for another application your process will be killed and its resources will be released.
If you free your cache each time your process is backgrounded, switching back to your application would no longer be fast because it would see cache-misses. This defeats Android's keep-background-processes-alive optimization!
You should just use the LruCache, which is also included in the Android Support Package for releases prior to Android 3.0 (Honeycomb).

Android, I see heap growing, but I want it to stop

I see my heap growing and I know it will eventually crash on any device since it just keeps growing.
Grow heap (frag case)
is seen throughout the logs
on my phone it will crash the app at 32mb used. Other phones will of course be 16mb, if there are any with that few resources that run android 2.2
Now, I am using recycle() on my bitmaps, setting things to null, popping items from complex data structures, and using System.gc() to invoke garbage collection, throughout the app
but, the heap still grows and its a problem... eventually
How do I just force the app to dump resources so that it can continue functioning.
it is usually always the "bitmap vm budget" exceeding, but I am feeling more and more that I just don't have access to the "clear bitmap vm" command
i had also struggled a lot with this issue. there are many a things you can do.
you can call recycle on each bitmap and set them to null.(bitmap.recycle() with relaese all the memory used by this bitmap but does not nullify the bitmap object ).
you can also unbind the drawables associated with layouts as specified in this link.
you can convert your hashmaps to WeakHashmaps. so that its memory would get relaesed when system runs low on memory.
you can resize all your bitmaps. have a look at this link..
you can override onLowMemory() method in activity which gets a call when entire system runs low on memory. you can release few resources there.
you can make your objects SoftReference or Weakreference, so that they get released in low memory condition.
But the real fact is that, all this can DELAY your out of memory issue/crash, but can not eliminate it because thing is that you must be leaking your activity context or memory somewhere.

What does Bitmap#recycle() in Android Honeycomb actually DO?

I am writing a very memory intensive application for Android Honeycomb, and I've been very careful to recycle() unused Bitmaps wherever possible; indeed, this is necessary for the application to work at all, as Bitmaps are constantly being cycled in and out of memory. However, I have just implemented onConfigurationChanged() in the Activity, and so (for a number of reasons) I am trying to put memory freeing routines in onStop().
Currently my onStop() method:
sets some Views to display a default Drawable;
calls recycle() on the Bitmaps previously used by these Views;
nulls references to the Bitmaps.
Unfortunately, using the Eclipse memory profiler, it seems this is having no effect on the memory usage at all.
As you can imagine, having made so much effort to free resources in a nominally garbage-collected language, I would have hoped for a little more effect. So my question is: what does recycle() do? Does it actually trigger garbage collection, or will the system hold on to the memory—even if you call System.gc()—until it feels the need to get rid of something?
NB I know Bitmaps aren't actually held in the regular heap but I thought calling recycle() was enough to ensure they were dropped out of the native heap.
PART OF THE ANSWER
I have discovered that if an ImageView contains a Bitmap that has been recycled, the Bitmap data is still retained in memory until setImageBitmap(null) is called on the ImageView. This may even be the case if setImageResource(...) or setImageDrawable(...) are called (they were, loading in a relatively small nine-patch—however, MAT analysis shows this did not remove the large Bitmap, which was contained in the private members of the ImageView). Simply calling this function at onStop() has culled about 10MB from the heap of our application. Apparently this may not be the case for pre-Honeycomb builds of Android, though.
As Justin says, 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. [Note that this may have changed in later Android levels, but is true for 2.1 and 2.2]
When you do a recycle() that marks both the small portion in the VM heap and the actual data in the native heap as free and available for GC. But the actual collection is performed by two different GC mechanisms. The portion in the VM heap is collected by the Davlik GC - and you can see that happening via DDMS. But the native heap data is collected by the Skia GC, which appears to be lazier (it runs less frequently?). That means that, even with rigorous recycle()s, it is possible to get ahead of the native heap GC.
Fortunately there are mechanisms to monitor the state of the native heap. See BitmapFactory OOM driving me nuts.
I have discovered that, in Honeycomb onwards, if an ImageView contains a Bitmap that has been recycled, the Bitmap data is still retained in memory until setImageBitmap(null) is called on the ImageView. This may even be the case if setImageResource(...) or setImageDrawable(...) are called (in this case, a very large bitmap was replaced with a fairly small nine-patch, but only when setImageBitmap(null) was called before loading the nine-patch was the memory actually disposed).
Recycle frees the native memory that is allocated to the bitmap. The actual Bitmap object will remain in the Dalvik Heap until the next garbage collection (but the memory taken up by this object is insignificant).
As far as I am aware, there really is no way to dump the native heap. So you won't be able to see if the bitmap's native data is gone via a heap dump. You should see, however, the total amount of memory your application is using go down. This question should help you discover the various ways to access the memory usage stats of your app.

Is there a way to compact memory in android to lower the high water mark?

Please note I do NOT have a memory leak. My question is about a subtler issue.
I recently wrote an android app which does image processing. The image is loaded as a Bitmap, then copied out in pixels, processed in a way that uses lots of memory (think Fourier transforms in floating point representations and stuff), then converted back into a bitmap and saved.
The problem is, through at least android OS 2.3, the total memory limitation (typically 16MB) is combined java and (externally stored) Bitmaps, and the java high water mark doesn't go down (that I can discern) even when the memory is free (successfully GC'd), which means when I go to allocate the final Bitmap, I am often "out of memory" even though by that point I have freed (and GC'd) most of the space. I.e., I never need the full 16MB at once, but the space left for Bitmaps appears to be 16MB minus the MAX historical java heap usage (as opposed to current usage).
I watched a tech talk by one of the android developers about memory issues and he implied this problem has been fixed in subsequent versions of the OS (they moved Bitmap memory into the java heap space), but in the meantime most of the people wanting to use my app are running 2.2 or 2.3.
Long story short, I am wondering if the java heap is ever compacted (de-fragmented, in effect) so that the high-water mark shrinks (and if so, how to make it happen)?
If not, then does anybody have another suggestion how to deal with this problem?
Long story short, I am wondering if the java heap is ever compacted (de-fragmented, in effect) so that the high-water mark shrinks (and if so, how to make it happen)?
Whatever its behavior is, it most certainly is not under your control.
If not, then does anybody have another suggestion how to deal with this problem?
Ideally, reuse your own Bitmaps. You don't indicate what "processed in a way that uses lots of memory" really is. However, if it does not change the dimensions or bit depth of the image, copy the data back out to the original Bitmap rather than allocating a fresh one, if you can.
Image processing on Android 2.x is one of the few places where I can see justifying using multiple processes. You will add overhead for schlepping the image data between processes, but the other process has its own heap (Java and native), so this may give you more "elbow room".
So far, no indication that there is any way to compact the memory.
Here is my workaround, which is suboptimal but much better than the behavior before:
I now intentionally hold on to the original Bitmap while I am doing my processing, and then recycle() and null it, and GC(), but not until just before allocating my output Bitmap.
What this does is reserve external (Bitmap) space, and cause my application to run out of java heap (during processing, before calling recycle()), which I can at least catch and handle by retrying on a smaller image. (Before, everything seemed to be fine until I tried to save, but by then it was too late and with no way to recover.)
Technically this limits my max image size to less than I should be able to do with the allotted memory (because I need to reserve space in the heap and external at the same time when in truth I never need both together), but at least I can still handle a reasonable image size.
What was happening before is I would free and recycle the Bitmap early which allowed the high water mark on the java heap to use up essentially all of my memory allotment, meaning from that point forward I couldn't open or create any more Bitmaps at all (other than tiny thumbnail sizes sometimes).
Imo, this is a major bug in the way android handles Bitmap memory, but I believe it is fixed in newer versions of the OS so hopefully I can disable this workaround conditional on the OS release.
I'm assuming that you already call Bitmap.recycle() but it's the only thing I remembered and you didn't talk about.

Categories

Resources