I am working on a cannon game for Android, which requires procedural generation of levels. As the player flies through the air, new sections get added on to the end of the level to keep it going indefinitely. As those sections are added, sections that the player has already passed are deleted. The problem is that the creation of a section usually leads to a GC_FOR_ALLOC, which pauses the game for around 30ms and causes noticeable lag.
The free memory stays fairly consistent, as objects are deleted while others are added, so there doesn't seem to be a memory leak.
The engine I am using is the cocos2D-android-1 port from iOS.
I saw many solutions along the lines of "don't initialize things while the game is running", but the nature of the level generation requires this, since an indefinite-length level can't be created right at the start of the game.
Thanks for your help!
You are not very specific. If the lag is too big, you must try to reduce it.
One way could be to collect more often - resulting in shorter, but more often occurring pauses.
For example you might create smaller or only partial sections and try to nudge the garbage collector afterwards to run. You would use System.gc() for this. But be aware that System.gc() is not guaranteed to result in it actually starting to run.
An even better solution would be to reuse objects. Objects that were created before the level was started. This way even an endless level would not result in any garbage collection since no garbage accumulates. But be sure to not create any non-pooled objects!
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()
I created an app in android studio that plots a graph(using mp android chart) from the data received from a source. Here's the problem: when I try to plot the data at high frequencies (like 150hz plus) the app slows down and then crashes. At lower frequencies it can keep plotting for as long as I like so I know its not running out of memory. Maybe it needs a minimum amount of time to clear its memory? Is their anything I can do that can help me clear the memory when I want?
You can call System.gc() manually to invoke garbage collection, but Android will still kick in a GC when you are running out of memory.
Note that a garbage collection can easily take 100ms and when you have a refresh rate of 150hz you only have 1000/150 = 6.667 ms for your calculations together with garbage collection. So your first step should probably be to check your object allocations and try to minimize those. (in fact, in your methods which are called every frame you should have no object allocations at all)
I'd like to ask the community what they think about this behavior.
On my main activity I have one FloatingActionButton that when clicked will show a DialogFragment.
I followed Google's guidelines (I can't link it due to being a new user here at Stack Overflow) on how to properly create a DialogFragment so I believe I'm OK there. I've tested this behavior on fragments that use either onCreateDialog and onCreateView, and in both cases the results are the same.
When I click the button and I look at the memory usage, this is what I see:
Memory when fragment is first showed
So Android is allocating additional resources to compensate for showing a new fragment. That makes sense to me.
However, when I dismiss or cancel the dialog, the allocated memory doesn't drop.
When I open the same dialog using the same button, the allocated memory jumps again. I repeat this over and over (red arrows) until my allocated memory reaches just under 10MB and then (I believe) the Garbage Collector (blue arrow) kicks in and cleans up the app:
Memory after multiple showings
To me, this means I'm relying on the Garbage Collector to do the work for me and from what I understand that is not good practice.
Can anyone tell me if this is normal Android behavior, or is there something I'm doing wrong? If It isn't normal behavior, I will try to resolve the issue myself first before asking the community for further assistance (this is why I did not provide any code).
Thank you in advance.
I think this excerpt from this page sums up this behavior nicely.
Android does not offer swap space for memory, but it does use paging and memory-mapping (mmapping) to manage memory. This means that any memory you modify—whether by allocating new objects or touching mmapped pages—remains resident in RAM and cannot be paged out. So the only way to completely release memory from your app is to release object references you may be holding, 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.
Basically, all you can do as an app developer is to release references to objects you allocate. So assuming you aren't keeping a reference to the object anywhere, like placing the fragment on the back stack for later use, the reference to the object should be released when the fragment is closed. At this point, it is available to the garbage collector to clear the previously allocated memory.
After that is done, it is up to the garbage collector to decide when to come in to action, so to say.
Good day,
I am developing an adventure game in AIR for Android. I am instantiating levels from the library (movie clips), each containing at least one HD resolution bitmap.
When the game starts, it occupies about 150MB of memory, including the AIR runtime and the SWF. Out of this 150MB the SWF is about 12MB at this time.
As the game progresses the memory consumption of the AIR runtime increases, while the memory used by the SWF remains at around 15-20MB. When the total memory consumption reaches about 350(!)MB, the OS intervenes and kills the app.
I was careful to reuse objects whenever I could, and nullify any unused objects to make them eligible for GC. GC seems to be working as it should, as the memory used by the SWF remains steady around 15-20MB. I can see it drop from 20 to 12 from time to time when GC kicks in.
Things I've tried:
Removed all cacheAsBitmap and cacheAsBitmapMatrix properties.
Exported each level into a separate SWF and loaded them from there instead of the library.
Forced the GC hack just to see if it has any effect.
Fiddled with System.pauseForGCIfCollectionImminent(n) with different values for n.
Tried different acceleration modes (direct and auto) thinking maybe the GPU is at fault.
All failed, memory consumption just runs away.
This happens only on Android. On a PC everything is fine, the whole thing takes up about 250-300MB, and this number remains steady, no matter how many levels I load one after another. Didn't have the chance to test on iOS yet.
I would really appreciate any ideas or insights into how to make this problem go away.
Thanks.
1) Easiest way to find memory leak is to use Adobe Flash Builder. Just run profiling.
2) Also good way to exclude leaks in future: create function which will be used for "cleaning". E.g. it will null all local variables of instance and so on. Something like usual c++ destructors. Then, before nulling your object, just call this method.
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?