Update: Adobe has added the Loader.unloadAndStop method to Flash player 10 to address some of the issues outlined in this article. You can find more details on this feature in my article “Additional Information on Loader.unloadAndStop“.
Flash Player 9 has a very dirty secret. It doesn’t even try hide this dirty secret, but it’s still not that widely known. You see, Flash Player has severe problems with separation anxiety – once it’s loaded some content, it has a really hard time ever letting it go. Technically speaking, it is extremely difficult to make Flash Player 9 unload ActionScript 3 content.
In this article, I’ll take an in-depth look at the issue, it’s implications, suggestions for addressing the problem in the player, and some workarounds for the time being. If this issue seems like it will impact your projects, I’d strongly encourage you to read through the article and educate yourself, then use the link at the end of the article to provide Adobe with feedback on it. Likewise, I would encourage you to share this issue with other developers, both to help spread awareness of the issue, and to give them the opportunity to also provide feedback to the Flash Player team. I see this as one of the most critical issues that should be solved in Flash Player 10, and the more people raise it as an issue with Adobe, the more likely it is to be addressed.
In my opinion, this issue breaks down into three problems: A major player bug, content sandboxing, and explicit unload functionality. Note that these issues affect content created with both Flex 2/3 and Flash CS3.
First, a little bit of info on the AVM2 garbage collector for those who haven’t read my previous articles about resource management in player 9. With ActionScript 2 content, calling MovieClip.unloadMovie() explicitly removes the contents of a MovieClip. This meant that your loaded content would immediately stop executing, and be removed from memory.
In AS3, calling Loader.unload() simply removes the reference to the loaded movie. If any other references exist to the loaded content, it will not be unloaded. Even when all references are removed, it only frees the content for collection by the garbage collector at some indeterminate point in the future. This means that even if everything worked as expected the loaded content will continue to execute, and remain in memory for an indeterminate amount of time after you unload it. This is problematic in many ways, but it is made worse by a bug in the player.
Flash Player 9 Bug
Flash Player 9 has a critical bug that prevents unloading loaded SWFs that have any active ENTER_FRAME or TIMER event listeners. This occurs regardless of whether these listeners are all within the scope of the loaded SWF, or even if they all use weak references. This also affect timeline code written in Flash authoring – if you have any code in your timeline, it will not be possible to unload that SWF.
AS3 lacks any support for explicit content sandboxing. By this, I am referring the ability for a developer to load a SWF into a sandbox, so that the loaded content can’t reach back into the loading application. This would be a very useful for a number of reasons, including loading third party modules or plug-ins without having to worry about them messing with things in your application. More important to this article though are the implications on unloading loaded content.
Firstly, content sandboxing would allow a developer to prevent a loaded SWF from adding listeners outside of its scope. This is important, because developers rely on stage events in AS3 for notification of things like global mouse movements, and key presses, but creating a stage listener from a loaded SWF will prevent it from ever being unloaded (unless it uses weak referencing). This is because addEventListener creates a reference back to the listener from the event dispatcher (in this case, the stage). This means that your content might never unload, and it means that third party content can (intentionally or not) prevent itself being unloaded by simply adding a stage listener.
Secondly, content sandboxing would allow the player to keep loaded content in a nice clean package, which I imagine would make explicit unloading possible.
As outlined in the background section, there is no way to explicitly unload loaded SWFs in AS3, which was very simple in AS2. There is a good reason for this â content can be referenced, instantiated, and re-parented across SWF boundaries in ActionScript 3. This makes unloading content much more complicated than it was in ActionScript 2. Still, the lack of this capability is a major downgrade from AS2, and makes some types of projects nigh on impossible.
I believe that content sandboxing would help address this issue, making it much easier to remove loaded content. Adobe could restrict the ability to explicitly unload SWFs to sandboxed content. For most applications that rely on loading and unloading content dynamically (galleries, for example) this would be an adequate solution.
These issues have some major implications, that affect three types of projects in particular:
- Gallery or portfolio projects. Some of you may have noticed that incomplet.org [Moved to incomplet.gskinner.com] stagnated as soon as AS3 was released. This is because it’s virtually impossible to create a site like incomplet.org in AS3. Because loaded content cannot be easily unloaded, it would mean that experiments would continue to run in the background after users clicked off of them. The whole site would slow to a crawl, and eventually crash. Not good. This is also the reason that in my upcoming FitC talk, I will likely have to resort to running my demos externally, instead of dynamically loading them and displaying them in the slides. Most likely this will prevent me from sharing my slides online as well, which is something I have been doing for years.
- Applications that load third party content. Any application that loads plug-ins, modules, or content from third parties is currently very problematic to develop. In order to do so, each piece of content must adhere to a strict coding standard, and expose a common API for deactivating the content. I feel there is also a bit of a security issue here, because the third party content can add a stage listener to prevent itself from being unloaded, then monitor all key and mouse interactions.
- Advertising. It’s currently impossible to safely embed AS3 based advertising into an AS3 based site. Most advertising uses timeline code, enterframe listeners, and timers, so if you have rotating banner ads loading into your Flash site, old banners will never stop executing or be removed from memory. Worse yet, if the banners are being served from within your domain, they pose a major security risk, as outlined in #2 above.
Part of what makes this so important is that it entails a reduction of capability from player 8 and AS2. It’s also weird messaging for Adobe, that Flash is awesome for building online experiences, and it’s great for creating online advertising, but it isn’t suitable for developing online experiences with advertising. It will also become increasing important as Flash / Flex sites become more modular, and with increased use of third party content and embedded ads.
Proposal for the Flash Player
At a minimum, I’d like to see the player bug resolved as soon as possible. I also don’t think it’s unreasonable to hope for some support for content sandboxing and explicit unloading for player 10. The API already has nice hooks for it.
To enable content sandboxing, Adobe could simply extend SecurityDomain to work similarly to ApplicationDomain, allowing developers to put loaded content into a new security domain, so that it cannot access the loading SWF. The nice things about this is that it wouldn’t require any new APIs, it would mirror an existing model, and there are already mechanism for dealing with this (this is essentially what happens when you load a SWF from another domain). We also already have a nice model for communicating with sandboxed content with childSandboxBridge and sharedEvents.
For explicit unloads, I would suggest simply adding a Loader.dispose() or Loader.remove() method. This could work just with sandboxed content, and throw an error if the content cannot be removed.
These changes wouldn’t directly solve every issue, but they would give developers the tools to address all the major problems themselves.
Work-Arounds and Strategies
There are four main things you can do to address these issues now:
- Make sure that you are always removing timer and enterframe event listeners in content you may want to load into a larger application. Also, try to avoid stage listeners where possible, and remove them immediately when you are done with them.
- Expose a standard API in your SWFs that allows other SWFs to tell it to clean up and stop executing. This way, the loading application can call this method (within a try/catch block) before it unloads any content. I would suggest a .halt() method, backed by a listener for a “halt” event through sharedEvents.
- You can load content SWFs from a subdomain. This will place it into a security sandbox implicitly.
- Load content into a div layered over your main application. This isn’t a great option, but it addresses almost all of the issues.
Providing Feedback to the Player Team
If you’d like to provide feedback to the Flash Player team on this or other issues, you can do so at this URL:
The player team is a group of smart, dedicated people, who are genuinely interested in what you have to say. They read every submission they get from that form.
If you do contact them about this issue, feel free to point them to this page for the explanation, but also let them know how this issue might impact your work.