Archive for August, 2009

What We Know About Unloading Modules

As of this writing, the Flex team does not know of any scenario that pins a module in memory forever assuming the developer has cleaned up all references.
If you have a module that does not unload, the steps to diagnose the problem are:
1) Make sure the module is being loaded into a child applicationDomain (use default parameters for the load() method in most cases)
2) Use the profiler to make sure there are no references to objects in the module. The most common causes of leaks are:

a. Styles. Even without any mx:Styles tag in your MXML, if a module uses a component that is not used by the main application, the module will register the default styles for that component with the StyleManager and pin the first instance of the module. You can use the -compiler.keep-generated-actionscript compiler option to see which default styles the module and main application are using. You can use the -compiler.keep-all-type-selectors compiler option on the main application to force the main application to register the default styles for every component in the defaults.css file. Prior recommendations to load style declarations via runtime CSS (StyleManager.loadStyleDeclarations) are withdrawn. Runtime CSS modules register styles in a different way so they can be unloaded and will not prevent this problem.
b. Resources. If a module uses components that use ResourceBundles that are not used by the main application, those resource bundles will get registered with the ResourceManager and pin the first instance of the module. You can use the -compiler.keep-generated-actionscript compiler option to see which resource bundles the module and main application are using. You can force the main application to have those additional resource bundles by adding the resource bundle metadata to the main application. For example, to add the “controls” resource bundle, you would add to the main application MXML file: [ResourceBundle(“controls”)] If you are loading your resource bundles as modules, make sure the resource modules have completed loading before loading the module that is being pinned.
c. ExternalInterface.addCallback. Modules should not use ExternalInterface.addCallback. That registers the method with the browser and there is no way to unregister it at this time. The recommended practice is to have the main application register a method that will call a function reference and put the module’s method in that function reference, then set the function reference to null when the module unloads.
d. Timers and other timer mechanisms. The use of Timer, setTimeout(), and setInterval() can cause leaks. Timer’s must be stopped and have their listeners removed, setTimeout and setInterval must be paired with calls to clearTimeout() and clearInterval().
e. Listeners to events from objects outside of the module. Use weak references or make sure to remove the event listeners. Remember, when you call a.addEventListener(“foo”, b.someMethod), it is ‘a’ that has a reference to ‘b’, not the other way. If you are listening to a parent or stage or singleton, those objects now have a reference to the object that whose method is going to get called and can cause leaks.
f. Focus. If an object in the module has focus, the FocusManager will still have a reference to the module. A good UI will move focus to some other object outside the module before removing the module.
g. RemoteObject. If a module brings in a data class that is going to be part of a server query, that class can get registered with the Player and result in a reference to the module. Link data classes into the main application when possible.
h. Loaded Images. If a module loads an image, that image must be unloaded otherwise the player will still keep some data buffers around.

3) Once there are no references to objects in the module, the Flash Player can still keep a module in memory for a while if objects in the module ever had focus. Other activity in the application, such as typing and clicking will eventually release references to the module and the module will be freed from memory. Try typing and clicking in the main application or another module and see if the pinned module gets garbage-collected.
4) Debug-versions of a module on the Debugger Player can also lead to a module being stuck in memory. Debug-versions contain debug information that can get registered with the debugger and not released. The final test is always to use release versions of the modules and application on a release version of the player.
A word (or 50) about unloadAndStop(): UnloadAndStop is a new API in player 10. It is intended to stop audio and video playback and the timeline, but does not claim to deference all references to classes in a loaded SWF and has not been proven to help modules free themselves from memory. While it may help child applications loaded via SWFLoader, it is not used by modules. Modules actually call Loader.unload() on themselves immediately upon completion of loading so that they will be available for garbage collection once all references to objects in the module have been removed. This is because a module can be used to make multiple instances of the various classes in the module and we don’t want to add the overhead of tracking all of those instances or require that a developer have some other way of tracking when all references to a module have been removed so they could know when to call unload().