What We Know About Unloading Modules

| 34 Comments

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().

34 Comments

Great information for develops who suffered memory leaking issues a lot. ~ Another reference trap could be with EffectManager, which holds static references of the last effect played/created, etc. And typically the effect instance has a reference to its target (could be components in a module).

thanks lot for the detailed list. i hope that these problems will be fixed soon by adobe. silverlight is already on the horizon as a serious competitor (see also what joa ebert wrote: http://blog.joa-ebert.com/2009/08/10/flirting-with-silverlight/) and i think with such weak points adobe will fall behind when it comes to build large scale robust applications, espacially when you consider C# as a much more powerful language then AS3.

Please help me with Flex technical queries.

I am using Flex Open SDK 3.3 in my project.

In Flex Runtime localization and running issue with the Flex repeater components, when ever I change my application locale
1. How to Handle of Flex repeater during localization?
2. Once I update the application locale how to update the repeater comp.

3 .what should be the best practice to update a MXML component or Action Script comp ?

2. How could I get the browser locale information and pass it to flex application.
In fire-fox the java-script works fine to find the locale before application starts, but in Internet Explorer the application gets already loaded before the script returns the value for locale.

I am using a jsp code to get the locale of the client browser.

Please provide us some best practice on passing browser information to flex application.

Nice to have: A single API which would return the browser locale

Browsed some examples in adobe site; but a small template would help us a lot.

Thanks for a very informative read Alex. A week or so back I was really struggling to get modules garbage collected and just couldn't get some to be GCd at all. This was due to the typing problem and despite typing in the main app they still didn't seem to get GCd but perhaps I didn't wait long enough.
We use remote objects in our modules. Will this stop the modules being GCd as well? Do we have to have all Remote Objects in the main application?
What is the recommended way of implementing styles now? Compiling them into the module and main app?


Thanks for these highly valuable information.
Concerning the poing g, I guess this has something to do with flash.net.registerClassAlias. Is there any way to manually unregister a class alias when a module is unloaded.

What about loading Modules? When loading a Module into my application with new nightly builds of the Flex 4 SDK, my Flex app framerate will drop to 0 and the whole application will get bogged down. In the first public beta of the Flex 4 SDK, this problem wasn't present.

Great article. I still have some problem with modules unloading. I'm going to implement all recommendation you give. Will see how it goes.
Thank you Alex.

Great article, it helped me alot.

I noticed though that if I have a datagrid with drag enabled and the user drags an item, then the module will not unload. Do you know why this would happen?

Thanks for the info Alex, the "ExternalInterface.addCallback" tip was the biggest eye opener.

I've also added one of our techniques on my blog: http://wp.me/pCFcS-r

Hi Alex,

Nice but somewhat worrying list...

we are building a huge app wich loads subapps (not modules but real separate applications build in flex). These subapps can be from third app developers etc... We use swfloader with the load for compatibility option set to true. This would mean that the sub app is loaded in a sibling application domain of the host app and that the subapp has it's own versions of all classes right?

Even if this architecture is more separated and less integrated than modules we still have a problem unloading the subapplication if we use styles in the subapp.

so if i call setStyle("color","red"); in the subapp, the subapp doesn't unload, removing the setStyle lets us remove the subapp.

The restriction "just not to use styles in subapps" is too big. Is there any option for flex 3.4 to fix this? I'd even go for monkeypatching the stylemanager if it's possible. Any help would be highly appreciated as i'm the one promoting flex/air and well, these kind of bugs can eventually lead to a technology switch as users of the system would run out of memory soon. I by no means want that!

thanx,

Arnoud

great and useful information for developers. the one great problem will be with the effectmanager since it show the last played effect.

Hi Alex, you can solve a lot of problems about modules patching some managers. For instance you talk about the focus, so if you take the implemetation of FocusManager you will find a variable called _lastFocus which stores a IFocusManagerComponent. Clearly this is a bad thing because if you try to removre a component it couldn't be disposed because there is someone who reference to it. So you can try to patch it using private accessor based on a weak dictionary with the component as key.

i hope it can be useful
thanks for your articles

Matteo

Thanks for this great info! You are definitely one of the smartest people I have found on this subject. Do you know of where I can go or could you post some examples of how to do points 2a, 2b and 2f. Also is there any material (books, tutorials, etc) on memory management practices. Any suggestions you might have would be greatly appreciated. Thanks again!

Hey Alex, great post about unloading modules, unfortunately this doesnt solve my problem of unloading a sub-application. Here's the code (it's really small):

(Replace ! with tags)
Main app:
!?xml version="1.0" encoding="utf-8"?!
!s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo"!
!s:layout!!s:VerticalLayout/!!/s:layout!
!s:Button label="Load" click="swfloader.source='TestAirSubApp.swf'"/!
!s:Button label="Unload" click="swfloader.source=null;System.gc();"/!
!mx:SWFLoader id="swfloader"/!
!/s:WindowedApplication!

Loads subapp:
!?xml version="1.0" encoding="utf-8"?!
!s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/halo"!
!/s:WindowedApplication!

As you can see my sub-app is nothing but an empty swf-the skeleton generated by new application. It doesnt have styles, timers or anything at all. Compiled with same version of Flex SDK, even putting it in a different appDomain or trying the release version, results are always the same. Every load increases memory per 1 instance and unload doesnt remove anything from memory. A memory leak. The only thing the subapp has are the classes from the Flex framework and even this dont get garbage collected, so how can I possibly solve this memory leak ?

Hey,
awesome article, really instructive. I translated it in french on my blog:
http://www.flex-tutorial.fr/2009/10/29/flex-modules-decharger-unload-correctement-ses-modules/

Thanks for the infos,
Fabien
http://www.flex-tutorial.fr

Am I write to assume from your list that if I have an application with one module required to perform some sort of remote request and then unload I must either (a) have the main application handle all the remoting logic (b) build a further second module to handle the remoting logic?

I guess that removes the notion of Modules who's sole role is to instantiate a Remote Object, handle the data and then unload?

What if the main app instantiated the Remote Object and various other classes referenced instances of this, would they be GC'd if they removed their instance on disposal?

Cheers,

Simon

Hi All,

I am struck up mid of something could you please help. I am using Flex builder 3 and Weborb PHP application. In which i am communicating via remote objects using web services.

Now my problem is i am trying to execute html file or swf but its giving error that its not connecting with weborb.php file. Whats the cause for this? where should i configure and execute.

Please help.

Thanks in advance
Jude

Another type of module leak is caused by modules registering singletons via Singleton.registerClass(). The class reference from the Singleton in the main application to the module pins the module in memory. The safest thing to do is always define PopUpManager and DragManager in the main application (see below).

import mx.managers.PopUpManager; PopUpManager;
import mx.managers.DragManager; DragManager;

I'm trying to figure out why my sub-applications won't unload. Can you explain this Object References table (I'm using the profiler in Flash Builder 4)?

_SeminarPlugin_mx_managers_SystemManager (2 Paths)
    Path 1
        _SeminarPlugin_mx_managers_SystemManager
        mx.core:FlexLoader - [child0]
        mx.controls:SWFLoader - contentHolder
        Function - [savedThis]
        flash.display:LoaderInfo - [listener0]
    Path 2
        _SeminarPlugin_mx_managers_SystemManager
        flash.utils:Dictionary - [key6]
        Class - allSystemManagers
        Object - SystemManager

Hi Alex,

When building our website - http://www.flexdownloads.com, we hit a number of issues using modules. Technical and architectural. We found them to be a bit buggy...contentions around which module loaded which Flex class first and also challenges around histoty mgmt, back button and bookmarking.

Finally, we had to give up and go without modules. Not sure if flex 4 changes things, but a small initial load is what most want for sure.

When you have some spare time, appreciate your visiting our website...its made in flex and for flex and intended to grow the flex community. Free is best but a bit of profit can be a strong motivator for the numerous developers out there so most of the components sell for under $10

Hi Alex,

First of all GREAT WORK! This clears a lot of questions.

Two Quick questions:

If Timers/Intervals must always be stop before removing them or clearing them. Why is it not built into the API to stop the timer when the remove call is made. Just wondering, if the thing is running and we know we wont be able to remove it if it is running why doesn't the API stops it automatically.

Second question is more of a few questions in one. Do all the things you mention above apply with relation to loading sub-applications? If not what are the differences.

Thanks again, and in advance for your reply.

Leave a comment


Type the characters you see in the picture above.

About this Entry

This page contains a single entry by Alex Harui published on August 7, 2009 10:14 PM.

More on Finding Memory Leaks was the previous entry in this blog.

Spark List + Spark List = Spark DataGrid? is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.