I was helping a fellow out in the Flixel forums with memory management before I realized this issue is serious enough to warrant a proper blogging. I hope Adam Atomic (creator of Flixel) will take note and include these fixes in the main branch (I posted a new issue on Flixel’s github). This information is also for other Flixel programmers who are deeply familiar with the framework and not afraid to get intimate with it.
The problem with Flixel’s memory management system is that it doesn’t exist. However, every time you switch states, it does call destroy() on almost every object. The problem is that most of the destroy() functions are completely empty. Obviously, this is not enough.
UPDATE: I got onto github and forked flixel, wrote a patch, and did a pull request. I can’t solve the biggest problem though, which is that FlxQuadTree is being completely recreated on every frame. This is extremely terrible practice and causing the Flash GC to bust ass. I don’t use FlxQuadTree and I recommend building a persistent static grid to handle collisions instead (MUCH simpler and faster than quadtrees anyway). I’m pretty sure the quadtree is causing a huge performance hit alongside the memory thrashing, since my games don’t experience what I see in vanilla Flixel. Good luck!
You will need to go through every class yourself and override (or fill in) the destroy() method to nullify any significant variable in the class itself. Remember to call super.destroy() so that it chains through all super-classes too. Here’s what the FlxObject.destroy() should look something like:
public function destroy():void {
velocity = acceleration = drag = maxVelocity = null;
origin = scrollFactor = null;
_point = null;
_rect = null;
_flashPoint = null;
colHullX = colHullY = colVector = colOffsets = null;
}
Don’t actually use the code in this post–none of it compiles without errors, it’s merely an example (I will be submitting a tested patch for this whole thing to the trunk soon). Also, I’m using the latest build I got from the Flixel homepage–v2.43.
What I’m showing here is pretty straightforward. It just nullifies all object variables so the Flash GC will pick it up. We do the same thing in FlxSprite.destroy(), but we’re going to have to add the function ourselves because for some reason it doesn’t exist. So put this function at the end of FlxSprite:
override public function destroy():void {
super.destroy();
offset = scale = null;
_curAnim = null;
_callback = null;
_flashRect = _flashRect2 = null;
_flashPointZero = null;
//_pixels.dispose(); // only do this if you don't use FlxG.addBitmap()
//_pixels = null;
_framePixels.dispose();
_bbb.dispose();
_framePixels = _bbb = null;
_ct = null;
_mtx = null;
for (var i:int = 0; i < _animations.length; ++i) _animations[i] = null;
_animations.length = 0;
_animations = null;
}
So those are the first classes to hit. But there are dozens more. Other ones you should get to include (but not limited to) FlxQuadTree, FlxGroup, FlxButton, FlxEmitter, and FlxTilemap. There are a bunch more in flixel.data that you need to do too, in addition to adding destroy code to FlxGame itself.
FlxG._cache and what it does
An important thing to note is FlxG._cache. Whenever you create a new sprite, it stores the bitmapData in that Object. Adam’s reasoning for this was so that only one instance of the BitmapData object remains in memory, so new sprites just reference that one instead of creating new instances. I think this is a pretty solid idea, but I’m not sure how much it actually helps. If anyone has tested this, please post your results in the comments.
Anyway, if you loop through it like I did with FlxSprite._animations though, you will get a ton of null reference errors because you already nullified most of it by disposing of _framePixels in FlxSprite. I recommend adding a new destroy function to FlxG itself and going through _cache and running dispose on each object regardless (IF it’s BitmapData AND not already null)… just to be sure. Don’t forget to null the _cache Object itself.
Cleaning up your own mess
It is very important to override destroy() in ALL of your custom classes to nullify any new variables you added in them. In every class you create, add a destroy() override that also calls super.destroy() in order to ensure that the GC picks up everything. Don’t forget to remove any event listeners as well!
So that’s the memory problem in Flixel and how to fix it. Please retweet this post and share it with others. I think this is an important issue that needs to address in a future version of Flixel, as others are always finding out about it and posting their troubles in the forums. Let’s do our part to keep Flash from crashing everyone’s browser
Thanks!







