I've found some information about the Android garbage collector that are contradictions to me.
Android Devevelopers Guide says:
Android 3.0 is the first version of the platform designed to run on
either single or multicore processor architectures. A variety of
changes in the Dalvik VM, Bionic library, and elsewhere add support
for symmetric multiprocessing in multicore environments. These
optimizations can benefit all applications, even those that are
single-threaded. For example, with two active cores, a single-threaded
application might still see a performance boost if the Dalvik garbage
collector runs on the second core. The system will arrange for this
automatically."
Ok, now the other thing
According to this link: The Dalvik Virtual Machine Architecture
android uses mark and sweep aproach.
The current strategy in the Dalvik garbage collector is to keep mark
bits, or the bits that indicate that a particular object is
“reachable” and therefore should not be garbage collected, separate
from other heap memory.
If we check how mark and sweep works on this link:
Mark and Sweep Garbage Collection Algorithm
, we can see this:
The main disadvantage of the mark-and-sweep approach is the fact that
that normal program execution is suspended while the garbage
collection algorithm runs. In particular, this can be a problem in a
program that interacts with a human user or that must satisfy
real-time execution constraints. For example, an interactive
application that uses mark-and-sweep garbage collection becomes
unresponsive periodically.
So my question now is, how does it really work? Does garbage collector pause everything while he is working, or is he capable of running completely independent on the other active processor core?
The Dalvik VM in the Gingerbread and beyond version is using the Mostly Concurrent partial collection garbage collector with pause times usually around 5ms. Therefore, yes, the GC is influencing the other apps by stopping them but the concurrent GC algorithm is able to minimaze these pauses.
You should look at :
Technical details of Android Garbage Collector
Does the DalvikVM Garbage Collector halt the whole VM?
In general, the Garbage Collection theory [Garbage Collection Wiki] explains:
Stop-the-world garbage collectors completely halt execution of the program to run a collection cycle
Incremental and concurrent garbage collectors are designed to reduce this disruption by
interleaving their work with activity from the main program. Incremental garbage collectors
perform the garbage collection cycle in discrete phases, with program execution permitted between
each phase (and sometimes during some phases).
Concurrent garbage collectors do not stop program execution at all, except perhaps briefly when the program's execution stack is scanned.
Complete independence is rather impossible: garbage collector and program use the same memory and have to communicate somehow. Even "pauseless" GCs, like Azul's (btw, a good read: http://www.artima.com/lejava/articles/azul_pauseless_gc.html), have technical pauses. Dalvik is probably (pure guess, based on anecdotal evidence and resources likely poured into JVMs during the last 15 years by the likes of IBM, Sun and Oracle) years behind the newest technology found in JVMs, so I suspect that the pauses will be longer.
It wouldn't pause other apps, it may pause your app. A mark and sweep doesn't have to stop all processing, its just the easiest way of doing it. It probably has some points where it pauses execution and other where it doesn't. THe only real way to tell would be to look at the Dalvik VM code. And I wouldn't count on it being the same answer in all versions of Android.
Related
One of the touted features of the ART runtime in Android 5.0+ is heap compaction, to reduce heap fragmentation. A fragmented heap can get OutOfMemoryErrors a lot easier, as there may not be a single contiguous free block of memory big enough for your needs, even if the heap overall has enough free space.
I understand that this occurs when the app moves to the background, based on Google conference presentations and the like. However, the only statement that I can find on it in the documentation says:
Homogeneous space compaction is free-list space to free-list space compaction which usually occurs when an app is moved to a pause imperceptible process state. The main reasons for doing this are reducing RAM usage and defragmenting the heap.
It's unclear exactly what a "pause imperceptible process state" means, technically.
Suppose an app does not have any foreground activities at the moment. Is there anything that the developer might have done that might prevent heap compaction for that app's process? For example, does having a foreground service block heap compaction?
Putting the pieces of the puzzle together.
From what I can determine, ART will compact anything that is paused for 2-3 seconds and by paused it means not currently running in background, so activities, but not running services. It will also compact on the fly, or concurrently while the app is in the foreground.
Currently, the event that triggers heap compaction is ActivityManager process-state changes. When an app goes to background, it notifies ART the process state is no longer jank “perceptible.” This enables ART do things that cause long application thread pauses, such as compaction and monitor deflation.
Chet Hasse states:
Garbage Collection
ART brought improved garbage collection dynamics. For one thing, ART is a moving collector; it is able to compact the heap when a long pause in the application won’t impact user experience (for example, when the app is in the background and is not playing audio). Also, there is a separate heap for large objects like bitmaps, making it faster to find memory for these large objects without wading through the potentially fragmented regular heap. Pauses in ART are regularly in the realm of 2–3ms.
From what I can see any pause in the app is fair game for the ART GC.
I suspect the app needs to be paused completely of all services, etc for the compact to occur, as it's reallocating the memory addresses of the heap, and for this to occur, it cannot be changing. As this larger compact that is taken during the app pause and not on the fly is a dynamic rearrangement of the heap. The only changes that can be made in the smaller pauses is to re-route some addresses on processes no longer being used.
Though this is an educated guess, not definitive and I will endeavour to get more info.
The source code here should have the answer. They're using naming like InJankPerceptibleProcessState() and trying to wade through this, as you probably already have yourself.
Reading it, will update answer when/if I find the definite answer.
Homogeneous space compaction is free-list space to free-list space compaction which usually occurs when an app is moved to a pause imperceptible process state. The main reasons for doing this are reducing RAM usage and defragmenting the heap.
Source : https://developer.android.com/studio/profile/investigate-ram.html#LogMessages
Actually you can measure the idle time of an app by. Start the idle timer and stop if if there is any event captured in TextWatcher/OnKeylistner, if you app is in background and none of these events are called, it is good to be collected by GC.
Also this heap contraction is event based and priority based. Eg if there is never a scenario when user need memory, OS will not even do it.
As far as priority is concerned, for garbage collection, it looks for background apps with no background service, then app with background service and at last the foreground apps.
I have several Async tasks throughout an app I'm designing. Several times an async task will run very slowly. Examining the log file shows that the desired background operation isn't actually causing the delay. The delay is that the background thread is held up by the Garbage Collection (davlvikvm). I'm not totally sure why there is so much GC happening in my app, it's not particularly memory intensive (no videos, just basic lists and a few images), and the MAT tool doesn't show any egregious memory violators. Regardless, I'm looking for a solution to keep my app running quickly to avoid long delays for the user.
I have tried to force the GC to happen earlier to avoid it, but it still runs at these inopportune times. My new thought is to tell the async task to run on a separate independent thread, so that it is not held up by the status of the GC. Is this possible? Is there a better way?
Thanks
I don't have a specific solution to your problem, but no, running your workload on a different thread will not change the behavior of your application during GC.
GC essentially stops the whole VM while it's working. The Dalvik garbage collector (since Gingerbread) is designed to minimize the pause time, but it still stops the entire VM.
For a little more detail, see Does the DalvikVM Garbage Collector halt the whole VM?
As far as minimizing GC pauses, there does not need to be anything 'memory intensive' as you have described. More often than not, the problem is with creating a lot of smaller objects. The way to minimize GC pause times is to minimize the amount of garbage that you create.
The best way to minimize garbage creation is to pool (re-use) objects rather than creating them, throwing away the reference (allowing the to be GC'd), and then creating another one, etc.
For an approach to doing this, see, for instance, http://www.devahead.com/blog/2011/12/recycling-objects-in-android-with-an-object-pool-to-avoid-garbage-collection
I'm writing a real-time arcade game for Android >= 2.1. During gameplay I'm not allocating memory, to not seduce GC. Beacuse if GC invokes, it takes processor for 70-200ms. User see this as "oh no, that game is lagging...".
I checked LogCat. There are lots of GC_FOR_MALLOC or GC_EXPLICIT. But... not from PID of my process! My game is not causing them. They're caused because other processes, running in the background. Some wallpaper, widgets, radio, email, weather checking and other services...
I don't understand it entirely. When, for example wallpaper dissapears, its onPause() is called, I suppose. So, it should stop all its threads and certainly do not allocate any memory (or call System.gc()). Maybe it's wrongly implemented? I don't know. But there are some Android services, which are also causing GC from time to time... It's odd.
Is it a big Android <= 2.2 architecture flaw?
Android 2.3 introduces concurrent GC, which takes less time.
What can I do to ensure that my game will run smoothly?
First of all, the things which you see in LogCat will differ from one device to another. If you are certain the GC is not coming from your app, you have absolutely nothing you can do. You will always find the GC doing..something.
Make sure you keep YOUR code clean and very lite.
Plus, remember that generally speaking, in the presence of a garbage collector, it is never good practice to manually call the GC. A GC is organized around heuristic algorithms which work best when left to their own devices. Calling the GC manually often decreases performance.
Occasionally, in some relatively rare situations, one may find that a particular GC gets it wrong, and a manual call to the GC may then improves things, performance-wise. This is because it is not really possible to implement a "perfect" GC which will manage memory optimally in all cases. Such situations are hard to predict and depend on many subtle implementation details. The "good practice" is to let the GC run by itself; a manual call to the GC is the exception, which should be envisioned only after an actual performance issue has been duly witnessed.
I do not believe it is a flaw on Android <= 2.2. Is it happening on higher versions? Have you tested it?
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 android application works well but it's performance(speed) is slow. In my logcat i saw frequent garbage collection operation like
11-02 15:07:20.647: DEBUG/dalvikvm(12571): GC freed 295 objects / 38448 bytes in 93ms
Is this the reason for low performance?? How can i improve my applications performance???
anybody please help
If you use the emulator don't worry - it is slow by itself. GC is not responcible for this i think, 93 ms is time you won't even notice. So try your application at the real phone and if there are preformance issues - use the profiler.
Your application performance in terms of user interface and memory is quite related.
In this case 93ms means that your device could be dropping about 6 frames in the ideal scenario. If the GC is executed often this could be a problem.
The Android ART/Dalvik virtual machine is a version of the Java Virtual Machine where the Garbage Collector implementation is based on generations. This means that your application process has a heap associated separated by different generations where the GC is going to act once a generation is full. You can think of these generations as buckets or arrays of memory.
Once a generation is full the Android virtual machine will start the garbage collector process. As the Android virtual machine can not collect and fragment your application heap while the app process is running the garbage collector event will stop all the threads in your app while the garbage collector is working. That's why your application can be dropping frames if the app garbage collector is invoked so repeatedly.
Here you have an example:
Last week I discovered my app was leaking memory. I discovered this because after 20 minutes using my app I noticed the UI was performing really slow. Closing/opening an activity or scrolling a RecyclerView was really slow. After monitoring some of my users in production using http://flowup.io/ I found this:
The frame time was really really high and the frames per second really really low. You can see that some frames needed about 2 seconds to render :S.
Trying to figure it out what was causing this bad frame time/fps I discovered I had a memory issue as you can see here:
Even when the average memory consumption was close to the 15MB at the same time the app was dropping frames.
That's how I discovered the UI issue. I had a memory leak in my app causing a lot of garbage collector events and that's was causing the bad UI performance because the Android VM had to stop my app to collect memory every single frame.
Looking at the code I had a leak inside a custom view because I was not unregistering a listener registered into a Android Choreographer instance. After releasing the fix, everything became normal :)
If your app is dropping frames due to a memory issue you should review two common errors:
Review if your app is allocating objects inside a method invoked multiple times per second. An example could be creating new instances of an object inside a onDraw custom view method.
Review if your app is registering an instance into the Android SDK but not releasing it. Registering a listener into a bus event could also be possible leak.
Disclaimer: The tool I've been using to monitor my app is under development. I have access to this tool because I'm one of the developers :) If you want access to this tool we will release a beta version soon! You can join in our web site: http://flowup.io/.
If you want to use different tools you can use: traveview, dmtracedump, systrace or the Andorid performance monitor integrated into Android Studio. But remember that this tools will monitor your connected device and not the rest of your user devices or Android OS installations.