Application Domain and External SWF Loading
Why do we care about application domains? I worked on a project that required me to load and unload SWF files into a bigger application (loading mini-games into a virtual world). Every time I loaded a mini-game, it would never unload when I exited it. That will keep accumulating until the app slows down to a crawl and crash because we’re out of memory.
The application domain and definition loading is one of the things that is not documented in a way the common mortal can understand. By popular demand, I will attempt to explain it the way I understand it. I will provide some examples along the way. Before I continue, here is a link to the official documentation on ApplicationDomain.
I will explain class definitions and domains, and then tell you what you can do to properly unload your movies and assets.
Class Definitions
Everything that you load has to be stored somewhere. It’s easy to understand the visual elements because you can just stick them on the stage. But what about class definitions?
For all of you who aren’t sure what class definitions are, remember all the classes that you import on top of the document when writing AS3. You can then instantiate your mx.controls.Button or flash.events.Event in the document. You can then add instances of visual components to the display list (stage).
Now think about your SWF for a minute. When you create a symbol in the library and export it for ActionScript, you’re basically creating a definition in the SWF. That definition will be loaded into some domain and you can instantiate it on the stage.
If you look at the schema, you’ll see all the class definitions in the current domain. When you close the application, all instances will be destroyed, class definitions removed and memory freed. If you decide to load an external SWF, you can choose where to load the definitions: in the same box as Class1 or in its own box.
ApplicationDomain.currentDomain
If you choose to load them in the same box as Class1, what will happen when you decide to unload your SWF? Any instances on that stage are destroyed, any definitions in its box are removed and memory is freed. Oh wait, there were no definitions in its box, so there’s nothing to remove from it. The file is unloaded in any case, but the definitions live on as a parasite in the box of our application. That’s right, a parasite. You can’t target a specific definition to unload. If you want to unload ClassC, you’ll need to unload the whole app (basically just close it). That’s not what you want to do. You want your app to run all day.
What is the solution? Remember there are 2 choices when loading your SWF. What if you want your loaded SWF to keep it’s garbage to itself? Sure.
New ApplicationDomain
So instead of loading you SWF into the application’s domain, load it into its own domain. How?
var appDomain:ApplicationDomain = new ApplicationDomain(); var context:LoaderContext = new LoaderContext(false, appDomain); var loader:Loader = new Loader(); loader.load(new URLRequest("myButtons.swf"), context);
We created a new domain and loaded all definitions into it. So now our application has 2 domains: the default one and a new one. You can create as many new domains as you have SWFs to load.
What will happen now if you unload your SWF? All classes are no longer in the same box, and the Loader that loaded our SWF has a reference to our new domain. That means that when you unload your SWF, the domain (box with definitions A, B and C) will be removed and memory freed. Yay!
Conclusion
So what does that all mean? Should we create a new domain for EVERY file that we load? Sure you can. But you shouldn’t. There are some nice functions such as getDefinitionByName() that I want to be able to use without searching for the domain in which my definition is contained. If I have a mini-game that requires 20 SWF files, searching for that little symbol in all these domains can be painful. I would rather create 1 new domain (say domainA) and load all 20 SWFs into it. Then I can access my symbol definition from domainA, and unload this domain when no longer needed. For a second mini-game, I’ll create domainB. The idea is not to stick everything into the application’s domain.
Please tell me if this post helped you with your memory usage. Also, feel free to add to my explanation if I missed something.
Thanx. This is great but i couldn’t understand the last part.
“Should we create a new domain for EVERY file that we load? Sure you can. But you shouldn’t.There are some nice functions such as getDefinitionByName() that I want to be able to use without searching for the domain in which my definition is contained. If I have a mini-game that requires 20 SWF files, searching for that little symbol in all these domains can be painful.”
What do you mean by little symbol.
Can you explain last part a little more
Thanx again.
Let’s take Super Mario Bros. as an example. You have different levels with different graphical themes, requiring a big number of assets (MovieClips, Sounds, etc.)
If you use 20 files for this game’s assets and you load each file into its own domain, you end up with 20 domains. It might not be easy to figure out in which domain the mushroom or coin MovieClip is located. It might be easier to have all of those files loaded into the same domain.
It’s really a matter of preference. Since all of these files belong to the same game, it’s not a problem if you load them all into one domain, domainMarioBros for example. Once you’re done with these files, you’ll unload them all and not individually.
Why bother unloading? Because if your Super Mario Bros. game is part of a bigger game/application, you want to make sure you free some memory for Duck Hunt that will be loaded next, otherwise your game might crash after some time.
Hi Anna.
You post is great.
Thx a lot. But i have little problem. can you please help me?
i have created a loader.swf and 2 other swf’s that will be loaded by loader. loader contains 1 class (myClass), which should be shared between 2 swf that should be loaded.
But when i try to share this class i see the next error:
TypeError: Error #1034: Coercion type error: unable to cast myPackage::myClass to myPackage.myClass.
at holdemLoader::HoldemLoader/OnGameComplete()
Did you tried to share any classes between different application domains?
Thanks a lot,
Valentin
By default, any domain is able to access ApplicationDomain.currentDomain, but not the others. If domainA needs to access a class definition in domainB, you have to explicitly point to that domain by calling domainB.getDefinition(…)
http://livedocs.adobe.com/flex/3/langref/flash/system/ApplicationDomain.html#getDefinition()
What exact statement leads to this runtime error?
Hi Anna. I am using application domains in a modular application. I have noticed that what I load an application in a new domain that contains a native flash component memory is never freed on when Loader.unload or Loader.unloadAndStop is called. Any suggestions as to how to get a flash components to release from memory in new Applicaiton Domain?
I’m not sure that the content of the loaded file matters. Make sure that all references from the main application to the loaded content is severed: visual elements removed from stage, any variables referring to the content cleared and any event listeners removed. Only then should you call the unload() method. I hope this helps.
Nicely written, Anna. You have a nice way of making the ideas comfortable.
I have two questions. First, could you elaborate on the idea of the “domain.” Your image suggests that a “domain” occupies a space “off-stage.” Is there a technical definition that explains that relationship somewhere?
Second, I have searched all over and have not found a clear explanation of how to call multiple independent applicationDomains. Does each context variable need it’s own unique variable name? Is how they are named significant in some larger scheme?
Thanks again for a well written tutorial.
Bruce,
Actually, the stage is contained within the domain, and not the other way around. I can’t find any official documentation that explains it in the way I like.
There is not need to store the context variable once you are done loading and the naming is not important. You may store references to your various ApplicationDomain somewhere, or simply access them using Loader.contentLoaderInfo.applicationDomain or DisplayObject.contentLoaderInfo.applicationDomain
Hi Anna,
Thank you for the post, very informative. I was hoping you could give an example on how to gain reference to a class in a separate ApplicationDomain. For example, I am building an avatar class and will want to load the avatar into the application swf, but in its own application domain. After loading it externally, I can create the class as follows:
var avatarClass:Class = info.content.loaderInfo.applicationDomain.getDefinition(“com.isointeractive.avatar.AvatarTypeBase”) as Class;
But when I attempt to create an instance, such as:
var test:AvatarTypeBase = AvatarTypeBase(new avatarClass());
I receive the following error:
TypeError: Error #1034: Type Coercion failed: cannot convert com.isointeractive.avatar::AvatarTypeBase to com.isointeractive.avatar.AvatarTypeBase.
The problem is that I’m trying to assign my variable, “test” to an object of the same type (AvatarTypeBase), but in a different application domain. Do you know how to resolve this? Thanks!
Hi Anna. It’s possible to change a class definition for a instance in runtime??
For example, i load a SWF with a class called SomeMovie in his own application domain. I create an instance of that class and add the movie clip using addChild. Then i load a second SWF with a class called SomeMovie too in his own application domain. There is a way to say at the instance that point to the class definition of the second loaded class ??
did you try with local files and with both parent / child files in the same folder..?
As far as I know, once a class is instantiated, you may not change its definition. You can always create an instance of the second class and then copy the properties from the first instance.
Since your classes are in different ApplicationDomains, they are considered as different classes, even though their names are the same.
You might need to rethink the architecture of your application to prevent assigning objects between different ApplicationDomains.
Hey, Great article and a million Thank You’s.
This seems to be the only article on the web which directly addresses the workflow that I would like to use for my game. I’ve been toying with the idea of building a level editor into a game I am working on. This would have meant that all the assets in the game would have to either be static or in the form of Sprite Sheets so they could be loaded at runtime and incorporated into the game. But now I can allow modders to use Flash Pro as their animation platform (which only makes sense).
I still wish Adobe would document a lot of these features though. So keep up the good work picking up their slack! ;P
Thanks for the explanation, it’s a great resource for fixing this issue. My problem actually came from loading external components I’ve created as individual SWFs in FlashDevelop, all with the main class as Main.as (default for FlashDevelop). The parent application’s main class is also Main.as, and it was quiet weird when running the SWF component individually would work fine, but loading it into the parent application would RELOAD the parent application AGAIN. Ugh!
Great article, I recently found my self troubleshooting the same problem, A virtual world with mini-games loaded into it. One of the problems was making sure that all resources were removed, even after I ensured that all listeners/bitmap/sound and everything else you normal check that keep a reference to an loaded swf, I still ran into the problem of the external swf not fully unloading. Perfect timing I must say.
Good article, very poor documentation from Adobe on application domain issues. I am loading a swf into a new application domain as suggested above, but only difference is i’m using LoaderMax, and when I unload the swf the application domain appears to be holding onto a reference to the swf as it can still access movieclips within it.
If anyone has had a similar problem I’ve posted a full explanation on the greensock forums:
http://forums.greensock.com/viewforum.php?f=6
Any help would be appreciated,
Thanks,
Scott
Thank you Anna. This helped me a lot. Marry Christmas from Germany.
You saved me, I love you!!
thanks a lot
THANK YOU SO MUCH!!!!!!!!
)).
You solved my problem, that i was fighting 2 days
You rock!
Thank you a lot ;D
I ususlly used two applicationDomains ,
one is the main ApplicationDomain and it contains the mainApp’s definations and rsls,
another is the subDomain which is inherit the main applicationDomain
(var appDomain:ApplicationDomain = new ApplicationDomain(ApplicationDomain.currentDomain);)
it contains the module class definations