More on Finding Memory Leaks

It seems that the most common scenarios involving memory leaks are the ones involving loading and unloading multiple SWFs like modules and sub-applications. Every day, we learn more and more about how the player manages memory and its other idiosyncracies, so it is time for another summary.
When debugging suspected memory leaks when loading/unloading SWFs, I generally do the following:
1) Set up the app or a test harness to load and unload the SWF multiple times (at least 3) and force a garbage collection pass after each unload or unload, then use the profiler to see how many copies of the module’s xxx_FlexModuleFactory or the subapplication’s xxx_SystemManager are in memory. If more than 1, keep loading and unloading and see if that number continues to grow. Any module or SWF that introduces a new component with styles will register those styles with the StyleManager and stick around forever the first time it loads. You can prevent that from happening by pre-loading the styles in the main app or via a CSS module. A second copy might stay around if it was the last thing loaded because the player or FocusManager might still be hanging onto it. If you see more than 2, that’s definitely a leak and you should use the profiler to find the leak.
2) After several loads and unloads, I take a memory snapshot, then do more loads and unloads and take another snapshot. I clear all filters, remove percentages, sort by class name and compare manually the number of instances of every class. They should match exactly, except maybe for a few Strings and sometimes, WeakReference. Everything else is suspect and deserves investigation.
3) Once I think I got all references to the SWF cleaned up, I next run several loads and unloads in the debugger and check the console. I am looking for lines in the debug output that start with:
[UnloadSWF]
That tells me that the player thought everything was cleaned up and unloaded the SWF. Note that it may not say that right away, even after GC requests as sometimes the player has internal references to a SWF that get cleaned up “later”. If I don’t see that, I go back to step 2 and compare memory snapshots looking for other things that might be leaking
4) Now that I’m convinced that even the player thinks it is ok to unload the SWF, if System.totalMemory is still increasing, the final test is to export release builds for all swfs and run them in a release player. The debugger player seems to hang onto debug information in the SWFs and can skew System.totalMemory. In recent tests, once I get past step 3, the release player’s reporting of System.totalMemory is much more acceptable, capping at a much smaller and acceptable maximum memory value.
5) Once you get past that, some of you might still see memory attributed to the player still growing when using OS tools to examine the player process. That remains an open area of investigation by the player team. For Internet Explorer, one often finds that minimizing IE causes its claim on memory to shrink, implying that it is something to do with IE’s memory management and not the Flash Player or your application. We don’t know of any way to programatically force IE to give up that memory. We also have seen reports of other browsers reporting memory growth even though Flash thinks things should be unloaded. If you can reproduce that in a small test case, file bugs with those test cases.

23 Responses to More on Finding Memory Leaks

  1. We worked on a huge flex application and we have had some serious problems with memory leaks.
    i think this topic is specially for air applications extremely important and adobe should really work hard on it that it will be improved soon.
    style handling should be designed the way that it cannot cause memory leaks and the developer does not need to hack around to prevent leaks. we have had problems with background-image in containers – after setting the style to null the leak disappeared.

  2. Tomek says:

    Thx for great article Alex, I always look forward to your in depth insight to Flex

  3. Patrick Lemiuex says:

    Is there ever a reason where memory would be used so much so, that a module won’t load, i have complex layout with a datagrid, and when i comment out the datagrid my module loads fine… Trying to figure out how to get around… any suggestions?
    ————————-
    Alex responds:
    I’d expect something else ot bust first. Are you sure the module isn’t already loaded? Are you sure you’re storing a reference to the IModuleInfo so it doesn’t get GC’d as it gets initialized? The DG might be the thing that fills memory enough that the module load forces a GC.

  4. Ed Syrett says:

    Hi Alex,
    As we’re talking about memory management, I have a specific question about FlashPlayer.exe. We will run our app on a Citrix server, so our clients will get a Citrix session running a browser. I was asked to look at running the app under FlashPlayer.exe to see if it had a smaller memory footprint.
    I ran some tests on my Windows XP machine where I just loaded and unloaded a large popup in our app – in I.E. 7 the total memeory reported floated around 120-150Mb, but when I loaded our app into FlashPlayer.exe, the memory footprint just went up and up…
    Is that what you would expect? I’m guessing that FlashPlayer.exe is just a test platform and isn’t really meant for a production environment..??
    Thanks,
    Ed.
    ———————————-
    Alex responds:
    I don’t think very many folks use FlashPlayer.exe to run a production app, but that has more to do with deployment than viability. I use it all the time for debugging since it is faster than bringing up a browser every time and it works fine for me.
    The debugger FlashPlayer.exe might have some memory management issues when working with debug SWFs, so the only true test is a release FlashPlayer.exe running a SWF exported for release build.
    It might be worth checking out the app in the profiler when using a debugger FlashPlayer.exe. It might also be that there was some dependency in your app on being in an HTML wrapper that is messing up cleanup.

  5. Fuzzo says:

    Hi Alex!
    I’ve read some Flex documentation and i’ve a serious problem: module unloading does not do anything and i don’t know why 🙁
    Here the example: an application loads a module with a timer. When i click “Unload” the module disappear from application but i can still see the traces “REFRESH n”.
    Why the ModuleLoader when unloading the module does not destroy and garbage collect it and all its children?
    ******************************************************
    ******************************************************
    ******************************************************
    ———————-
    Alex responds:
    A module must not have any more references to it before it can be unloaded. Calling unload() just removes the reference to the bytes in the SWF. You have a Timer event listener that the player is keeping track of, so it has a reference to the module.

  6. Gewy says:

    Alex, if I understand you, having more than 2 xxx_FlexModuleFactory instances is a leak, and having [Unload SWF] in the debugger prove everything is OK an nothing prevent the module unloading.
    What about the case where all instances of the xxx_FlexModuleFactory stay in memory AND the [Unload SWF] appears in the debugger trace. BTW the System.totalMemory of the Player show a memory leak.
    Thanks,
    Gewy

  7. Adriano says:

    Hi Alex
    I’m using FB4 Beta and Flash Player 10 on XP and i have a panel like this:
    >>>>>>>>>>
    <?xml version=”1.0″ encoding=”utf-8″?>
    <s:Panel xmlns:fx=”http://ns.adobe.com/mxml/2009″
    xmlns:s=”library://ns.adobe.com/flex/spark”
    xmlns:mx=”library://ns.adobe.com/flex/halo” width=”400″ height=”200″>
    <fx:Script>
    <![CDATA[
    import mx.containers.FormItem;
    import model.Person;
    import mx.controls.Alert;
    import mx.core.IVisualElement;
    import mx.core.FlexGlobals;
    public static const SAVE:String = “SavePerson”;
    public var person:Person;
    protected function closeButton_clickHandler(event:MouseEvent):void
    {
    person = null;
    removeAllElements();
    focusManager.setFocus(FlexGlobals.topLevelApplication.openWindowButton);
    FlexGlobals.topLevelApplication.removeElement(this as IVisualElement);
    }
    protected function showButton_clickHandler(event:MouseEvent):void
    {
    person = new Person(new Number(txtID.text), txtName.text);
    dispatchEvent(new Event(SAVE));
    }
    ]]>
    </fx:Script>
    <s:layout>
    <s:VerticalLayout/>
    </s:layout>
    <mx:Form id=”form”>
    <mx:FormItem label=”ID” width=”350″>
    <s:TextInput id=”txtID”/>
    </mx:FormItem>
    <mx:FormItem label=”Name” width=”350″>
    <s:TextInput id=”txtName”/>
    </mx:FormItem>
    </mx:Form>
    <s:HGroup>
    <s:Button id=”showButton” label=”Show Saved Person” click=”showButton_clickHandler(event)”/>
    <s:Button id=”closeButton” label=”Close Window” click=”closeButton_clickHandler(event)”/>
    </s:HGroup>
    </s:Panel>
    >>>>>>>>>>
    When i’m profiling i opened the window, clicked showButton and closeButton, gc collects the panel ok, but when i opened and clicked on TextInput then closeButton gc doesn’t collect the panel, has a leak when i put focus on a TextInput. Can be styles? Some system listener? help me please.
    PS: My MainApp only have a button to call this panel and Person is a simple AS Class with id and name
    Thanks in advance.

  8. Alex Harui says:

    I’ve never seen that happen. Are you sure the unloadSWF was for that module and not some other SWF? If you force a gc and refresh do those instances go away (and make sure you aren’t looking at cumulative instances). The profiler should help you find who is holding onto those instances

  9. Alex Harui says:

    See the post on unloading modules.

  10. Adriano says:

    All Listeners are cleared, App doesn’t use styles, no timers, no external resources, no remote objects, before clear i put focus outside panel… Something was leaking when my InputText has Focus 1st time, something that i don’t know how to destroy… If i don’t focus my InputText, the panel was cleared by GC… Could be something in SDK?

  11. Alex Harui says:

    It could be the player. The unloading modules post says that the player can hold a reference to an input control and sometimes it takes more user input transferring focus to another control to free it. If the SDK was holding onto it, you’d be able to see it in the profiler. If there are no valid backreferences to an input control but it isn’t going away, it could be this player issue. Tab to other controls and click on other controls and see if it eventually gets GC’d

  12. Adriano says:

    Hi Alex,
    I did new tests and i found when my app is leaking. I tested comboboxes, checkboxes, datagrids and my panel gets GC’d. The problem is when i set focus to a component and the blue border appears like textinputs, textareas, colorpickers, richtexteditors. I exported a release build and profiled as external app with no success. What can i do to resolve this? Could be a player issue?
    Thanks in advance

  13. Alex Harui says:

    Yes that sounds like the player issue. If you tab around to different controls the objects should eventually get GC’d. If it doesn’t, verify that there really are no references to objects in the SWF.
    You will not get accurate findings profiling a release build. You only use release builds on release players once the profiler no longer shows any problems.

  14. Hong says:

    Hi Adriano,
    Did you find a fix for your memory leak issue(focus on TextInput)? I have same problem. I tried to call some codes to let TextInput lose focus but still not helping, eg:
    mytextinput.focusManager.deactivate();
    mytextinput.visible=false;
    mytextinput.visible=true;
    Not sure why the last two lines needed, just found it from some site.
    Hong

  15. Joan says:

    Hi Alex,
    I’m developing a webapp that loads (on demand) all the metadata of a database in a tree. This tree is using a treeItemRenderer that loads several embeded images depending on the type of node and other info for each node (labels, checkboxes, statistics…).
    This tree uses a huge amount of mememory, up to 1gb when everything is loaded. Would you think this is normal?
    Thanks.
    Joan.

  16. justin says:

    Hi Alex,
    Have you any experience with loading/unloading Flash SWFs? I am loading SWF files generated with Flash CS3, and although I have achieved removal of all references to the instance of the loaded SWF – called “FlashSubApplication” – and its sub-components, I am seeing references to fl.managers.FocusManager as well as fl.managers.StyleManager. To be clear – when I unload the SWF, in the Live Object view I still see an instance of my FlashSubApplication. When I take a memory shapshot after the unload, I also see FlashSubApplication in the list of classes for the snapshot, with one instance. In the Object References view however, there are NO references to FlashSubApplication. Since it is dereferenced, shouldn’t it be GC’d?
    I am also aware of an issue with Flash Components – ths sub app contains some fl.Buttons instances – in which a referencet to Stage is created, which apparently can’t be worked around other than to not use Flash Components. Still, the instances of the fl.Button are also gone in my snapshot after the upload, as are the Button skin instances.
    Then there is the matter of the fl.FocusManager and fl.StyleManager instances, which do have references. And while the registerInstance() function of the fl.StyleManager makes sense to me in that it points to a Button instance, what about the fl.FocusManager?
    If I remove the Button instances from FlashSubApplication, all of the problems are alleviated, and the memory is GC’d on unload. Left in the Live Objects view however is 1 instance of the FlashSubApplication, but it consumes zero memory.
    All of this is so unfortunate. We should have done what I suggested in the beginning, which was to do content replacement on a div so that our app never actually loads anything. I really love Flex and Flash, but things like this are going to hurt developers like me in the short run and Adobe in the long run if they are not addressed.

  17. Alex Harui says:

    It could be expected depending on how much data and images you are loading, and how many rows in the tree are visible. The profiler can help you get a handle on whether you have leaks.

  18. Alex Harui says:

    The rules and principles are the same. If the sub-app has references to itself it won’t unload. It might be that fl.FocusManager was not designed to be in a sub-app. Even in Flex, we require that many of the singletons be created in the main app.
    I trust the snapshot more than live objects. Live objects can show false counts for things like try/catch blocks and anonymous functions. I just review the snapshot to make sure there aren’t any objects whose call stack references code in the sub-app.

  19. justin says:

    Just wanted to say thanks very much for taking the time to reply. It is sincerely appreciated.
    Thanks!

  20. Pablo says:

    I have the same problem with flex Ariano but in 3.5, anyone know if it could resolve please adriano

  21. Adriano says:

    Issue continues, i really don’t know why… If someone has the answer please show us!

  22. Vishnu Jakhoria says:

    Hi Alex,

    I am working on a large enterprise application built in Flex (SDK 3.5). I have read your blog on Flex memory leaks & working of GC in Flex. Through profiler I know that my application has some memory leaks but the question that struck in my mind is the behavior of the Internet explorer browser. The memory consumption by the browser for the application goes to more than 1 GB while using the application and then it crashes. If I minimize the browser (IE ver. 6.0) it releases memory and goes down to 10 folds of the actual allocation. (From 850MB actual allocation, on minimizing the browser it went down to 75MB!!!)
    But this happens only with version 6 of the Internet Explorer. The other later versions Internet Explorer i.e. 7,8,9 does not releases memory at all on minimizing. Therefore my question is if in case my application is leaking memory to a large extent then how IE6 can free up the memory??? And minimizing the browser is not a solution to free up the memory. Is it problem with Internet Explorer on allocating memory to the Flash player??? Any help regarding this issue is highly appreciated.

    Thanks.!!

    • Alex Harui says:

      The first goal when dealing with memory leaks is to get the profiler to say that nothing is leaking. Only when you get that far can you start worrying about what the browser says its memory usage is.