Reasons why garbage collector takes all cpu time on each frame
Asked Answered
I

2

5

Some times my adobe air application becomes very slow because garbage collector starts to work continiosly on each frame and takes more then 800% of budget. it lasts several minutes or even more. This problem appears only on iPhone 4/4s from time to time and after restarting device everything works correct for some time.

Maybe somebody also has such situation and know the ways how to prevent it?

UPDATE: object pools and other allocation-prevention approaches already implemented. So there's nothing really to collect and GC is just spending CPU for nothing. When this ends memory usage is still the same. Also it does not happen every time even if same input and scenario is used. So I suppose there's some 'unlucky' situation with allocated heap being around some threshold where AIR decides to make clean up before taking another chunk from the system. Then it found few objects to dispose and no new chunk is required again. On next frame few objects are created (very few) and scenario is repeated.

Profiler screenshot

Inwrought answered 20/2, 2014 at 8:45 Comment(4)
I think you should check out THIS PAGEJacquelinjacqueline
Make sure you correctly release all event listeners you add throughout the app, otherwise it will eventually screw up like you see.Pushup
Are you calling System.gc() anywhere? You can manually call garbage collection using that method in AIR, though it is highly recommended you not do it. Regardless, without seeing some kind of code, I don't think we will be able to help much here.Geisha
how much memory is the app using?(iOS had some limitations) You mention that each frame a few small objects are created are those objects correctly released(remove event handlers) also can you use a pool for those objects too? If you are using FlashBuilder there is a memory profiler that could help. If you use the memory profiler are there many objects in the heap?Testament
V
4

A few points to keep in mind:

  • Garbage collection only kicks in when your app requests memory; Flash will try to recover some memory from your app before requesting another memory page (an allocation of around about 1MB) from the OS. Because your garbage collection is kicking in quite often, it suggests that your app is taking up more memory than you think
  • The GC works based on references: var s:Sprite = new Sprite() creates a reference to a Sprite. var s2:Sprite = s creates another reference. For the memory that your Sprite takes to be considered for garbage collection, both s and s2 need to be set to null. If they're local variables, this will happen automatically when they go out of scope (e.g. if they're declared in a function, at the end of the function)
  • Once all references to an object are cleared, the allocated memory can be recovered. Sometimes, however, you can have a problem with circular references - where 2 objects hold a reference to the other, but nothing has a reference to them
  • To get around this, the GC has 2 phases, generally speaking: the mark phase, and the sweep phase. The mark phase will start at the root of your app (the stage), and try and touch every object that it can. Everything that's not touched is assumed to be dead and can be collected. All "dead" objects are cleaned up in the sweep phase.
  • The mark phase is super slow, so you want to try and avoid it as much as possible, by essentially keeping your memory use static.

To help the GC:

  • Clear your event listeners, or use weak listeners (which don't add references)
  • Clear your explicit references - implement a destroy() or a dispose() method that you call when you want to get rid of something, and null everything that's an object
  • As mentioned, reused objects using an object pool
  • Some objects, like BitmapData and XML can be immediately destroyed (BitmapData.dispose() and System.disposeXML()). If it's only used for setup, or can be reloaded, get rid of it. NOTE: if you're using Starling, and you create Textures from Bitmaps, then you probably don't need the original, unless you want to deal with lost contexts, but you can probably just load everything back in.
  • Be careful of hidden allocations: cacheAsBitmap is allocating a bitmap in the background, ditto for filters; Array.splice() is creating a new array etc
  • Watch out for any object creation that happens in loops etc

I wrote a class ages ago to help track memory leaks (http://divillysausages.com/blog/tracking_memory_leaks_in_as3), but you should be able to get even more in-depth using Scout - take a memory snapshot, play around a bit, then take another one; you can compare the two and highlight any created objects, including (I think) where they're being created.

Another point to keep in mind is if your device actually has enough memory to run your app in the first place - e.g. if your app (assuming everything is optimised etc) takes 100MB of memory, but you only have 80MB available, the GC will be continuously running to try and allocate the last 20

Vita answered 1/3, 2014 at 23:59 Comment(1)
This is an extremely good answer. I definitely give it a thumbs up. To further add to this, I suggest reading the articles and using the tools created by former Flash evangelist Grant Skinner. gskinner.com/talks/resource-management gskinner.com/blog/archives/2006/09/garbage_collect.htmlGeisha
T
3

Try using an object pool so you recycle objects.I am assuming you create lots of objects then the GC tries to release the memory, if you recycle the objects then you will not create new ones and the old ones do not need to be collected. If my assumtion is right using theis object pool pathern will improve your application performance and may solve your issue.

Testament answered 20/2, 2014 at 11:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.