I have read Android's Developers Guide on Designing for Performance.
I am just wondering that if I have a large object, that I cannot avoid creating (which is expensive ) , it seems logical that I want to deallocate it immediately when I know I am done with it.
There seems to be no way of doing this.
Some suggest setting it to null so it will be immediately GC by the system, will this be truely "immediate"? Because if the system (Dalvik VM) has the option to NOT deallocate the large object that I just set to null, then setting it to null is not at all a solution.
Is it correct to say that setting it to null will ENCOURAGE and SPEED up GC?
Is this approach a "good enough" way to optimize Apps performance? Or is it worth going the extra mile (if at all possible ) , to force GC whenever applicable to squeeze the best performance out of any Android device?
I don't think you should worry to the granular details when GC is executed as we don't have control over when gc gets called. Even calling gc() will not guarantee a collection. Per documentation from System.gc()
Indicates to the virtual machine that it would be a good time to run the garbage collector. Note that this is a hint only. There is no guarantee that the garbage collector will actually be run.
In developing the application with large object allocation I would worry about the following instead:
Upon allocating the large object and subsequently after exit the scope of life cycle of that object, do I see it get reclaimed by the GC in later Activities? This could be easily checked by running dumpsys meminfo with adb shell. You basically check after deallocation if the memory is properly garbage collected typically signify by large spike and drop afterwards
Check if this large object has a clear path to GC. You could do this by checking the reference path of this object via dumping the hprof and check it in Memory Analyzer. If it does, you are safe as the GC will smart enough to collect.
After I allocate this large object, do I have enough padding in my heap to execute subsequent activity? If the object is too large, there is a chance that GC is not fast enough to collect it (this is actually related to your point) and the memory consumption from subsequent activity combined with the left over from the previous ones might actually cause out of memory error. Setting null with a clear path to GC will help to ensure that this object will get GC'ed appropriately. I admit this is a problem, but my view is if this becomes a problem, we might have to relook on how this particular section is designed and see if we could do any optimization on it.
Implement clean up on the activity via onDestroy as necessary and make sure the Activity is not referenced by others so it could get properly garbage collected. For example: we often pass activity context around forgetting that it will hold its reference. Things like calling recycle() on bitmap should also help. Remembering these points should help preparing more space in the case of #3 happens
Most of the time android does a good job of handling garbage collection. I wouldn't worry about it unless you start receiving a OutOfMemoryError.
But if your really worried about it,setting the object to null and then calling System.gc() will most likely cause it to be collected.
Related
I'd like to know some simple code that allows for freeing used memory that is no longer needed, in a similar way as a lot of memory freeing apps do.
Yes, I'm aware that this shouldn't be neccesary because Android manages memory on its own, but it looks like what's causing a non desired behavior in my app is having a lot of opened app occupying memory, so I think this is worthwhile to try, and check if the error happens any longer.
Could anyone hand me such a code? I'm not able to find any.
What I gather from the article is that you don't need to do anything to reclaim memory, but you can make garbage collection happen quicker and at specific times. What this means to me is that any arrays, Lists, large objects, etc. should be set to null when you are done with it. Granted, this should be done automatically when you leave a method or a View, but in case you are in a long running loop or staying on a page with lots of data hanging around, you can clean it up a little faster.
The Android Runtime (ART) and Dalvik virtual machine use paging and memory-mapping (mmapping) to manage memory. This means that any memory an app modifies—whether by allocating new objects or touching mmapped pages—remains resident in RAM and cannot be paged out. The only way to release memory from an app is to release object references that the app holds, making the memory available to the garbage collector. That is with one exception: any files mmapped in without modification, such as code, can be paged out of RAM if the system wants to use that memory elsewhere.
https://developer.android.com/topic/performance/memory-overview
You can also check your memory usage to see if that's really the problem. This is linked in the article above, but I thought I'd pop it out so it's easier to notice.
https://developer.android.com/reference/android/app/ActivityManager.html#getMemoryClass()
According to Android Reference Document of Bitmap.recycle():
Free the native object associated with this bitmap, and clear the
reference to the pixel data. This will not free the pixel data
synchronously; it simply allows it to be garbage collected if there
are no other references. The bitmap is marked as "dead", meaning it
will throw an exception if getPixels() or setPixels() is called, and
will draw nothing. This operation cannot be reversed, so it should
only be called if you are sure there are no further uses for the
bitmap. This is an advanced call, and normally need not be called,
since the normal GC process will free up this memory when there are no
more references to this bitmap.
But, many books I read suggest to free memory by calling Bitmap.recycle() once make sure no longer need it.
It make me confused: Is it needed to call Bitmap.recycle() after used?
It depends.
If you run your app on Android 3.0 and above, it's not needed as the GC will take care of it perfectly.
However, if you run your app on older versions, since bitmaps don't get monitored well by the GC (it thinks they are the size of a reference), you could get OOM, as shown on Google IO lecture here.
In any case, it's still recommended to call recycle as soon as you are sure you don't need the bitmap anymore. It's good even for new android versions, since it lowers the work needed for automatic memory management...
In fact, I remember I've asked a similar question here.
Also, if you need extra control of bitmaps using JNI, check out this post.
So, in short, the answer is that it's not needed anymore, but still recommended.
EDIT: Ever since Android 8.0, Bitmaps are stored in native memory, so it's harder to reach OOM. In fact, it's technically impossible, as you will get into other issues instead. More information about this can be found here.
In my experience, we run a heavy Bitmap compression in production code, and without calling recycle() we run into many OOM Exceptions in old Lollypop devices, and after adding it to the code, the number of OOM reduced significantly.
It is not necessary, but is highly recommended! It will speed up the memory freeing process and will save you of torture with Out Of Memory exception.
I would say its mandatory if you are going to do any serious an memory extensive work with Bitmaps.
Prior Android 3.0 Bitmaps allocs native memory to store it's pixels, and the recycle() calls delete in that region.
Even with that the GC ins't guaranteed to free up that memory if there's still any references for it.
But this call looks like that helps GC to work better, I developed an app that does extensive usage of memory and running in newer devices calling that or not the app run nearly the same (for older it really improves some performance).
What is the difference between the heap usage (Allocated) we can see in the Elipse Memory Analysis Tool (in the DDMS view) and the memory usage size for the same App shown here on the Android device?:
Settings->Apps->Running
Even though I aggressively tried to preserve memory by making objects null as soon as they weren't needed, the latter number (memory usage size on Running apps screen) only kept increasing and my app finally crashed due to OutOfMemoryError. However, the former showed me that I was well within a reasonable size. I was also calling System.gc() a lot. Is there a difference between the two? Why the discrepancy? Any ideas on how I can solve this problem?
The biggest difference between the two that I know of is the scope of garbage collection.
Normal garbage collection, including System.gc(), collects a bit of garbage, then stops. It is not a complete sweep of the heap to get rid of everything. That is to try to minimize the CPU impact of garbage collection.
The heap dump prepared for MAT, though, effectively a complete GC.
Your symptoms suggest that you are allocating memory faster than GC can reclaim it. The primary solution for this is to try to allocate less memory, or allocate it less frequently. For example, where possible, reuse objects, bitmap buffers, and the like, instead of trying to let GC clean the old stuff and allocating new stuff as you go.
It sounds like you have a memory leak somewhere in your application if the memory is never released. This means that somewhere you are maintaining a strong reference to a large object which is being recreated (like an Activity or Bitmap) which is why calling System.gc() is making no difference.
I suggest watching the following on memory management in android from google IO 2011. It lets you know how to use the eclipse memory analyser tool which is incredibly useful for debugging this sort of error
I have an OpenGL Android app that uses a considerable amount of memory to set up a complex scene and this clearly causes significant heap fragmentation. Even though there are no memory leaks it is impossible to destroy and create the app without it running out of memory due to fragmentation. (Fragmentation is definitely the problem, not leaks)
This causes a major problem since Android has a habit of destroying and creating activities on the same VM/heap which obviously causes the activity to crash. As a strategy to counter this I have used the following technique:
#Override
protected void onStop() {
super.onStop();
if(isFinishing()) {
System.runFinalizersOnExit(true);
System.exit(0);
}
}
This ensures that when the activity is finishing it causes a complete VM shutdown and therefore next time the activity is started it gets a fresh unfragmented heap.
Note: I realise that this is not the "Android way" but given that the garbage collector is non-compacting it is impossible to continuously re-use the heap.
This techinque does actually work in general, however it doesn't work when the activity is destroyed in a non-finishing mode and then re-created.
Has anyone got any good suggestions about how to handle the degredation of the heap?
Further note: Reducing memory consumption is not really an option either. The activity doesn't actually use that much memory, but the heap (and native heap) seem to get easily fragmented, probably due to some large'ish memory chunks
Fragmentation is almost always a consequence of an ill conditioned allocation pattern. Large objects are frequently created and destroyed. In conjunction with smaller objects may persisting (or a least having a different lifetime) - holes in the heap are created.
The only working fragmentation prevention in such scenarios is: prevent the specific allocation pattern. This can often be done by pooling the large objects. If successfull, the application will thankfully acknowledge this with a much better execution speed as well.
#edit: yet more specific to your question: if the heap after a restart of the application is yet not empty, so what is there to remain on the heap? You confirmed that its not a problem of a memory leak, but this is, what it seems. Since you are using OpenGL - could it possibly be, some native wrappers have survived, because the OpenGL ressources have not properly been disposed?
My activity keeps a certain number of references to preview images from the camera in a Map object. This takes a lot of memory. I'm monitoring the memory usage using:
Runtime runtime = Runtime.getRuntime();
long allocated = runtime.totalMemory();
long free = runtime.freeMemory();
long used = allocated - free;
When I kill my app (back key), the activity is destroyed. When I start my app again, I can see that the memory was not cleared. The "used" figure starts at the same value and then goes up as new frames arrive.
When I look at the "dominator_tree" after I "Dump HPROF", I can see two instances of my activity, both taking a lot of memory.
When I override onDestroy() and I clear() the preview frames map object, this doesn't seem to happen.
I'm probably missing something here but I thought all memory should be deallocated after my activity is destroyed (after the garbage collection process), why do I have to manually clear() the map? Other objects I create don't seem to require this.
I tried setting android:launchMode="singleInstance" but this doesn't seem to have any affect.
Thanks!
in order to understand what's happening, in the dominator tree, on your activity click with the right button, look for PATH to GC ROOT and select the option that exclude weak/soft/phantom references. That would give you an idea why the system could not destroy your activity (if you are leaking something or what else)
Garbage collector will run as needed, at an indeterminate time chosen by the runtime. GC may or may not run when your application exists.
However, if your objects still stay in memory after GC is run it means you are leaking memory. You can check the logs in logcat while debugging to see when it is run.
For a good tutorial how to detecting and fixing leaks check Android Memory Management Video from Google.