Ted Patrick - Demos & MAX @ Adobe Systems


Note: This is the personal blog of Ted Patrick. The opinions and statements voiced here are my own.



Memory Performance in the Land of References

DIGG IT!     15 Comments Published Wednesday, July 15, 2009 at 9:46 AM .

Over the past few years I have seem my share of memory related issues in working with Flash Player and AIR. In every case, the issue always boils down to reference handling in that somehow code was written (typically innocently) that holds a reference to an object indefinitely. In all systems with a garbage collector memory system, you need to be very careful how you work with object instances. Lets look at the details:

var arrayRef:Array = new Array();

Here "arrayRef" is a reference holding a newly created Array object instance. Within the Flash/AIR VM, "arrayRef" is actually a reference to raw block of memory within the player. Whenever you want to do something with the array instance, you use the "arrayRef" reference to read/write/execute properties and methods of the object stored in memory.

The real fun begins when references are passed around within the system like so:

//direct reference
var arrayRef2:Array = arrayRef

//property reference
var objRef:Object = {};
objRef.foo = arrayRef;

//event reference via method closure
mylistener.addEventListener( "woot" , customMethodOnReference );

//In AS3 all methods have "closure" and thus hold a reference to the object instance. If you pass methods, you pass an object instance! Method closures are a handy feature but they have reference implications attached. Be careful!


The lesson here is that you can pass references very very very easily, maybe too easily, and thus unless you are tracking down all instance usage, you will see app memory accumulate. This is especially true with application data objects where lots of data flows into the player via the network and data is consumed by an application. Each object created via network operation must be carefully watched and managed.

In terms of memory consumption no object is more problematic than XML/E4X. In Flash Player XML and E4X are an object with a collection of inner objects. They are trees of objects all with internal references. When they are used, you need to be careful how you access them and reference the objects they contain. If you set values based on data within XML/E4X, you will hold the whole XML object in memory unless you release the objects. There are a few reports of "Memory Leaks" within E4X when using certain XML features (I AM WRITING ANOTHER POST ON E4X and LEAKS...STAY TUNED) and some of these are bugs but a large majority seem to be misuse of reference of result XML objects. How you use the references within an XML object is really important and developers need to be careful what they hold onto. I tend to create new Model objects from E4X data queries and never reference internal E4X objects directly in code. This has helped my projects as a practice.

Flash Player and AIR release memory when all object reference to an objects are gone (not counting internal reference). The garbage collection occurs incrementally so as not to slow down the player as it processes ActionScript and renders graphics. The garbage collector within AS3 works via deferred reference counting backed by incremental conservative mark/sweep collector. For detail on the VM and Garbage Collector, this PDF is the best guide I know of. When objects are created you will see memory consumption rise within the Flash Player (via flash.system.System.totalMemory) as new memory is allocated from the system to the runtime. Player and AIR maintain a buffer of available memory for newly created objects and if there is nothing to collect (recover memory) the player will get more memory from the system. This will show up in the Profiler as rising memory but you will never see this value fall (via flash.system.System.totalMemory). Once memory is acquired by the player for use, it remains used and is recycled using the garbage collector. The key here is that you need to lower instantaneous memory consumption within your application and be very careful to allow the player to garbage collect over time. Adding too many objects at once will force player to generate new objects and acquire system memory if the buffer isn't enough.

Long story short, you have full control of memory use within your applications through careful objects creation and reference management. The problem is it isn't automatic and you need to be careful with references.

Regarding E4X memory issues, I am planning to post this week on the issue.

Manage your references!

Cheers,

Ted :)

15 Responses to “Memory Performance in the Land of References”

  1. # Blogger hebchop

    Genius. Thanks. Not enough people know this, I know I'm guilty of dumping xml and creating tons of objects on init. I should work smarter:) Thanks for the reminder.  

  2. # Blogger raffjones

    Great post there... thanks very much. Big hints from this end are - 1. use weak reference for listeners!!! 2. GET FLEX BUILDER (soon to be Flash Builder) PROFESSIONAL... the app profile and the ability to trace loitering objects is fabulous.  

  3. # Blogger Christian Nunciato

    Indeed, thanks for the info. I've seen a lot of folks complaining about AIR applications as "memory hogs" lately, but the applications they cite are usually active web-service consumers (e.g., Twitter clients), so it's probably just a common unawareness of these details that's bloating their apps and contributing to that perception. +1 for raffjones's suggestion of using weak references, too -- I almost never attach a listener without a weak reference anymore. Curious, though: as an Adobe insider, any hint as to why that's not the default behavior, or why it's not suggested more often in tutorials and the like?  

  4. # Blogger Ted Patrick

    A major issue with network operation is listeners. Typically network classes and the results are temporary variables with listeners. Once the last "complete" event occurs all the listeners should be removed else the network object and the results within are hung in memory. It is a simple but very fatal error in most apps.

    A good solution would be a class that managed all this for developers, buffering them from dealing with these easy to fix cases.

    IMHO weak reference should be the default case but it isn't although I am sure there is a great explanation as to why.

    Ted :)  

  5. # Blogger Robert Penner

    Re: "This will show up in the profiler as rising memory but you will never see this value fall."

    Can you expand on this? How then can you tell the difference between successful garbage collection and not?  

  6. # Blogger Ted Patrick

    Robert,

    flash.system.System.totalMemory
    The amount of memory (in bytes) currently in use by Adobe® Flash® Player or Adobe® AIR®.

    This provides totalMemory allocated to player but doesn't provide detail on how it is used. Within the Profiler this gets broken down in detail. I have seen many complains about rising memory via the totalMemory value which is expected behavior.

    In early AVM2 APIS (Flash Player 8 target) there were totalMemory and availableMemory. AvailableMemory showed the buffer that objects were created from. This was a bit confusing so it was changed as things headed for 9 release. The profiler breaks this all out though clearly. I will edit to post to make note of this.

    Ted :)  

  7. # Blogger Robert Penner

    That makes more sense, thanks.  

  8. # Blogger Troy

    Re: Why are listeners not "weak" by default?

    I've come to learn (the hard way) that if you add weak listeners to a local variable the object will potentially get cleaned up before your listener ever fires. The solution is to either use the default, non-weak listeners (which will hold a reference and prevent GC) or to store the reference somewhere other than the stack (so it won't go out of scope when you exit the function).

    I assume that listeners are "strong" by default to avoid this pitfall as it's nearly impossible to debug if you don't know to look for it.

    Re: Flash Player's memory allocation from the OS...

    Ted, any idea at what point the Flash Player will return memory to the OS? Does it ever? I've got an app that has a huge peak memory utilization (during startup) but then drops significantly. It appears, though, that the Flash Player continues to harbor all that memory it needed briefly, even after the browser window is closed (but the browser app isn't exited, e.g. OSX).

    I would hope (expect!) that the Player would return memory to the OS at least once the browser window (or rather, the SWF container) was removed. This seems problematic for the Flash Player in general (my app in particular) under systems like OSX where users may not exit their browser app for days or weeks.  

  9. # Blogger Nuno R

    It means that if i create a bunch of objects in a short time span, the memory requested from the system will never be released by FP until it closes, even if after some time only uses like 20% of it?  

  10. # Blogger Ted Patrick

    Troy,

    Flash Player will keep all the memory it is allocated until the process ends. The player just like most VM's never returns resources to the OS. The key is that allocation ( OS to Player ) and GC within Player are very different. One gets memory to use, one recycles memory within the runtime.

    The only way to manage memory is defensive preventive minimalistic use. Writing sloppy code that generates 10K objects will have an impact on player performance and the memory use profile.

    Use the resources player provides carefully and you will never have an issue.

    My 2 cents,

    Ted :)  

  11. # Blogger Tyler Wright

    Event listeners are one of the more common references that go unnoticed, so it's nice that weak-reference is an option. However Flex binding is the other big one and doesn't feature weak-reference, so must be carefully cleaned up.

    But there's an open source weak-reference binding solution that replaces the BindingUtils - I think Adobe should take inspiration and add weak-reference binding to the Flex Framework. xtyler.com: Custom Binding It's been one of the best contributing factors to managing memory leaks for me.  

  12. # Anonymous mbucc

    Good post, kind of hard to find this stuff around.

    Does using the toString() also avoid holding a reference?

    var x:XML;

    var attr:XML;

    var s:String;

    x = <a><b>1</b></a>;

    for each (attr in x.b.*)

        s = attr.toString();


    I assume it must, but could not figure this out definatively.

    Thanks!  

  13. # Blogger codecraig

    when's the e4x specific post coming :)  

  14. # Blogger Ted Patrick

    I have been working with several folks internally to isolate/confim my findings. It is taking longer than I planned, but I would rather get it right than post early. Sorry for the delay.

    Ted :)  

  15. # Blogger cindy

    Any idea when the e4x post is going to come out?  

Post a Comment

Where to find me:

Ted on Twitter - @AdobeTed
Ted on Adobe Groups
Ted on LinkedIn
Ted on Facebook
Ted at Adobe


Latest

Lists

Links

Jobs

Flex Jobs
city, state, zip

Archives