Ah, the joy of the first tech post in this blog! Don’t worry, it will be a quick one, and easy too. This post speaks about memory management, some issues that I had in UFHO with memory and persistency of objects, and the conclusions.
In every programming language, there’s an entity called garbage collector which handles memory and frees it from unused variables. Now, everyone knows that, in Flash, there’s no manual garbage collection. That is, you can’t say to the player “Hey Flash Player, I’m done with this object, release it from memory”… no way! Everything is automated, which is cool at the beginning.
What the player does is to check periodically for objects that have no references, and remove them from memory. What is a reference? It can be a couple of things. Let’s see:
private function getGlobalPosition(_clip:DisplayObject):Point
var theGlobalPoint:Point = new Point(_clip.x, _clip.y);
The point of this simple function is to get the global coordinates of an object passed as a parameter.
The Point object created inside the function has a reference pointing to it as long as Flash is still executing the code inside the function. As soon as the function exits, the Point object is marked as eligible for the garbage collector, because there’s no more references to it (so it’s, in some way, unuseful). At the next pass of the garbage collector, it will be released from memory.
The Display List
Another way of keeping an object in memory, is to add it to the Display List. Example:
var theClip:MovieClip = new MovieClip();
Compared to the example above, even if the function has ended, the MovieClip created here will not be released from memory until we call a removeChild on it. That’s because, otherwise, the object would disappear as soon as the function has finished its tasks.
Objects can have many references, and the Flash Player keeps track of them all and moreover, it keeps track of their number. When an object has 0 references, it is garbage collected. There’s another way to have an object collected though, and it is to leave 0 references for the object that references to it (its parent). For example, if you create a MovieClip and then add a child inside it, when you remove the parent clip from the display list, both are eligible for garbage collection.
This is called sometimes an ‘island’, because the isolated movieclips, while still connected together, are cut away from the mainland… the mainland being the stage (for the graphics) or the document class (for classic references). If a group of object is not added to the display list or doesn’t have any reference to the document class, they are removed from memory.
This, is the tricky part, and where I met problems in making UFHO.
The basis of event management, the addEventListener function, is a mischevious one. After adding a listener to an object, even if you remove that object from the stage and delete all references to it, it will still be kept in memory because a listener is still… listening for something. Even if it can’t be clicked (MouseEvent), it may still do something like send ENTER_FRAME events.
That is why you should always call removeEventListeners when you are done with an object, so you don’t have that object stuck in memory and you don’t know what caused the memory leak.
In my classes, I usually have a method that is responsible for removing all the listeners from an instance. You can remove listeners without any fear, because differently from removeChild, which yelds an error if you try to remove a clip which is no longer in the display list, removeEventListener will not give any error. So it’s safe to try to remove anything and everything, and if the event listener was already removed… no problems!
private function removeListeners():void
(graphicalBoard.stage != null) ? graphicalBoard.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onDragUpdate) : null;
Anyway, for the removeChild error, there’s a quick patch: just check if the DisplayObject’s stage property is null, and if it’s not, remove it from its parent. This way you don’t even have to remember from which clip to remove your object.
Notice how I remove the MOUSE_MOVE listener from the stage only if the graphicalBoard stage property is not null (that is, the graphicalBoard is still on the stage).
I also use this for special effects clip: I put on the last frame of the clip this code:
This way the clip will automatically remove itself from the display list, and also stop its timeline. This is because… I fear that if you don’t stop a clip, sometimes, it will stay in memory. I made some tests and I’m not sure about the results, but better to prevent than cure!