Garbage Collection in a MultiCore Modular Pipes Application
Garbage collection (gc) in Flex/Flash for Flash Player 9 is a well known issue that has seen to be resolved in Flash Player 10. But as with all player upgrades its not always a simple process for companies out there, especially large size corporations therefore I have my hands tied with using Flash Player 10 in some of my clients apps.
So I was not overly surprised to note an increase in memory in a PureMVC MultiCore application that loads and unloads modules and utilises the Pipes utility. This was, however, something that I needed to tackle with the prospect of some of my modules being welter weight in size and thus on repeated loading and unloading had the potential of bringing a system to its knees (ok slight exaggeration).
A period of time ensued with the primary focus to try and tackle this problem. MultiCore apps with the addition of Pipes can throw in a few extra ties necessary for removal, being that its complex enough to perform all household cleanup chores for an efficient gc, the thought of removing incoming/outgoing pipes, mediators and cores can appear daunting. But it can be done and you know what, it ain’t that hard!
Reading through the PureMVC forums is an awesome way to feed off ways some people have started to tackle this issue and two dudes I fed off in the RIA/Flex/PMVC world offer awesome examples, feedback and guidance which is a must read for getting a grasp on MultiCore so check Jens Krause and Joshua Ostrom. Jens props for your tip on the definition of a clean up method in the IPipeAwareModule Interface and thanks to Sean Christmanns blog post on gc.
Phase one:
I managed to remove the necessary pipes, mediators, listeners, etc and ran a removeChild in the main application shell to remove the module and a removeCore to remove from the MultiCore framework. To check the total memory that the app consumed I ran System.totalMemory and used the invaluable Flex Profile.
Result:
Loading and unloading a module repeatedly caused a continued increase in total memory used…. damn!
Phase two:
A usual problem is running order of a sequence of events. Having a good old reference read of Colin Mooks Essential AS3 got me thinking that this could be a potential root to my lack of success, I also noted that he stated to perform removeChild() right at the end of performing all cleanups within a module. I was running removeChild prior to removeCore() ?!?
Bring on a review of the running order of cleanup, ensure time is allowed for this to occur then run removeChild() to remove the module.
Result:
:) it works! Load, unload a module, repeat, repeat, repeat….. System.totalMemory() is now showing no increase whatsoever!!!!
Conclusion:
There is an initial spike (dependent on module size) in total memory on the first load/unload which I am told is the code remaining in memory, this is of no major significance in my eyes due to the amount of data being retained.
The way I have tackled it is to define a method in an Interface to clean up garbage (similar to what Jens has done) and also dispatch a note to remove the module, these 2 work their way through the framework clearing and nullifying as much as possible with the garbage collection running behind the remove module note. When I instantiate both calls I also set a Timer event which should leave enough time for them both to do their house hold chores then I run a System.gc() and repeat then finally removeChild!!!!
GC still remains unpredictable (see above links) and I do not think that there is a 100% guaranteed solution but I think there is a good chance that this should enable the best shot possible to enable it to work.
Here is a mini demo application built using the PMVC MultiCore framework which demonstrates very simply (a) how to set up a modular app (b) how to integrate a the Pipes utility and communicate between a module and shell (c) how to load a module and (d) how to unload the module, perform gc and display the total memory used pre and post module removal. View Source is available. On testing I managed to get it to work effectively on each test run, others testing found that it at times did not gc (see above statement) so I have also integrated some interactivity to adjust the Timer length between performing household chores and performing gc and removeChild(). There is also a option to increase the amount of calls to flash.system.System.gc() and a quick total memory check option to see if gc is happening too late :)
Expected result should be the pre/post total memory panel displaying from the second load/unload onwards the same value for post garbage collection.
http://www.newtriks.com/apps/flex/PipeGarbageCollection/GarbageCollectingPipes.html
* Notes *
You will not see the benefit of this process until you export a release version in Flex as opposed to running the debugger version.
Garbage Collection in Flash Player 9 (I feel) still maintains elements of unreliablity, however, in comparing two of my applications one most definitely resulted in memory bloat when unloading and loading modules, the second application did not! SUCCESS :)
Other Reading:
http://developer.mozilla.org/en/docs/MMgc#How_MMgc_works
Getting started with PureMVC: http://www.newtriks.com/?p=352.