If you have a SWF that you know will be loaded into a parent SWF, then it’s your responsibility as a developer to properly clean up after yourself when your child SWF is unloaded. Certain activities will keep your SWF in memory long after the unload()
method is called on the Loader
object that holds your child SWF, and there’s a good chance that you’ll have created a memory leak if you don’t take care of things properly.
It’s important to note that in Flash Player 10, Loader
has a new unloadAndStop()
method that does some of this work for you (see Grant Skinner’s blog post about unloadAndStop()
for detailed information). While that’s helpful for SWFs that you don’t control, I think it’s still very important to clean up your own SWFs as best you can manually. Obviously, you have no other choice if you’re still targeting Flash Player 9.
What sorts of things could cause problems when you’re trying to unload a SWF? Running Timer
instances, enterFrame
events, audio or video that’s still playing or streaming, MovieClip
instances that are playing, and content loaders that have not completed yet are all good examples (see Grant’s post above for a longer list). Some of these activities don’t actually keep your SWF in memory, but it’s important to remember that your SWF may not be garbage collected immediately. Code that’s still running for no good reason is simply a waste of resources.
How to clean up after yourself
A SWF can discover when it has been unloaded by listening for Event.UNLOAD
on its loaderInfo
object. This event handler is the perfect place to do your cleanup. I’ve put together a couple of very simple classes to illustrate how this process works.
First, we have the aptly-named ParentSWF
document class for the SWF that loads our second SWF as a child. It’s very simple. It instantiates a Loader
to load ChildSWF.swf. When that Loader
has completed, it has some code to unload ChildSWF.swf right away:
package { import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.net.URLRequest; /** * This is the document class for a parent SWF that loads, then unloads, a * child SWF. It is part of a demonstration of how child SWFs can clean * up after themselves up when they are unloaded. * * @author Josh Tynjala (joshblog.net) */ public class ParentSWF extends Sprite { public function ParentSWF() { super(); //this loader will load the child SWF. Upon completion, it will //immediately unload the child SWF. this._loader = new Loader(); this._loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loaderCompleteHandler); this._loader.load(new URLRequest("ChildSWF.swf")); this.addChild(this._loader); } private var _loader:Loader; private function loaderCompleteHandler(event:Event):void { this._loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, loaderCompleteHandler); this.removeChild(this._loader); //this is where we unload the child SWF this._loader.unload(); this._loader = null; //at this point, the child SWF should be ready to be garbage //collected. only the child SWF can keep itself in memory now. //it had better clean up after itself! } } }
Next, let’s take a look at ChildSWF
, the document class for our second SWF that is loaded into the first SWF. It includes a running Timer
that should be stopped when the child SWF is unloaded. We listen for Event.UNLOAD
on loaderInfo
to know when the parent SWF has unloaded the child SWF:
package { import flash.display.Sprite; import flash.events.Event; import flash.events.TimerEvent; import flash.utils.Timer; /** * This is the document class for a child SWF is loaded in a parent SWF, and * then unloaded. It is part of a demonstration of how child SWFs can clean * up after themselves up when they are unloaded. * * @author Josh Tynjala (joshblog.net) */ public class ChildSWF extends Sprite { public function ChildSWF() { super(); //we want to listen to Event.UNLOAD so that we know when the Loader //in the parent SWF has unloaded this SWF this.loaderInfo.addEventListener(Event.UNLOAD, unloadHandler); //this timer, if still running, will keep this SWF in memory after //ths SWF is unloaded. this._timer = new Timer(1000); this._timer.start(); } private var _timer:Timer; private function unloadHandler(event:Event):void { //stop the Timer or this SWF won't be garbage collected this._timer.stop(); //of course, make sure to remove this event listener too! this.loaderInfo.removeEventListener(Event.UNLOAD, unloadHandler); } } }
To be perfectly clear, the most important parts of the child SWF code above can be summarized in the snippet below:
//listen for the unload event to know when all activities in this SWF should be stopped this.loaderInfo.addEventListener(Event.UNLOAD, unloadHandler); function unloadHandler(event:Event):void { this.loaderInfo.removeEventListener(Event.UNLOAD, unloadHandler); //DO YOUR CLEANUP HERE! }
Again, let me cover some of the most common things that should be cleaned up. Be sure to stop audio and video that is playing, MovieClip instances that no longer need to be playing, Timer
instances, tweens (they’re probably run by Timer
instances or enterFrame
events), active listeners for any type of Event.ENTER_FRAME
, listeners for events coming from the stage
(also a good place to use a weak reference), and be sure to stop any data that may be loading from external sources using URLLoader
, Socket
, Loader
, and other classes of that type. If your child SWF has it’s own child SWFs, be sure to unload those too!
That’s a lot of stuff to remember! Yes, it is, and it’s your responsibility as the developer to ensure that nothing in your SWF causes a memory leak, just like it’s your responsibility to do the same for your individual classes. If you’ve designed the rest of your application with good memory management, then it might not be as bad as you think. Often, you only need to take care of objects that are referenced in the document class. Those objects should already be doing their own work to cleanup any references and event listeners that aren’t needed anymore. For more information on that subject, check out the excellent series of blog posts about AS3 memory management by (once again) the very knowledgeable Grant Skinner.
It really make lots of trouble if the swf (which is going to be loaded by another swf) does not implements the Event.UNLOAD listener!!
Thanks for the info!!
hi,
is there any which will handle the closing of swf window in flash….??
regards
fks