So after doing some further tests I was able to pinpoint code that would result in memory leaks. The code itself looked harmless and functionally it worked.
I narrowed a leak to a “doSomething” function in my Util class. I knew it caused an error because when I turned the function into a no-op the leak went way. So I knew that something in that code was causing the leak. But just looking at it, it made no sense whatsoever why there was a leak.
Example original code:
public static function doSomething(clip:MovieClip):void
{
var mc:MovieClip;
do some sort of gotoFrame logic on clip
for all children in clip {
if child is MovieClip {
mc = MovieClip(child);
doSomething(mc);
}
}
}
This code recursively does something on a movieclip and all of its children that are also movieclips.
public static function doSomething(clip:MovieClip):void
{
do some sort of gotoFrame logic on clip
for all children in clip {
if child is MovieClip {
doSomething(MovieClip(child)); // cast child and send
}
}
}
Notice that I removed the local variable “mc” and just passed a MovieClip casted version of child as the parameter. There was NO functional reason for this change. I really had doubts that this would have any affect. After all, “var mc:MovieClip” is a local variable and should be marked for garbage collection at the end of the recursive function call. The function does in fact end so don’t think it’s runaway recursion. We’re dealing with clips that are just 3 subclips deep at most and I use this function several times a second on many clips without any hanging.
When I tested the second version of the code there was no leak to be found. Undeniably the code change had some effect. Why?!? My theory was that since I was calling this static function from inside a non-static instance of an object that maybe Flash had some obscure rule about local variables inside static functions and it caused the program to hold on to all references to MovieClips thus preventing them from ever being garbage collected.
I don’t pretend to know everything there is about Flash or how it works. But something about this seemed real fishy. I often like to blame flash for its bugs but I do this mostly to complain about the IDE. I like to trust that the flash player is solid and without error… yeah, so naive. It’s not a good practice to blame the flash player because then you may write off real issues as “flash bugs” when in fact they are your fault. I try hard to give flash the benefit of the doubt. I’ve done so for this entire week. I’ve torn apart my code to pinpoint the causes for memory leaks. I’ve been rebooting my game practically one feature at a time just to find issues. This is how I found the issue mentioned above.
Even though I felt a little relieved that I’ve finally “fixed” one of the leaks, something didn’t feel right about that fix. I didn’t feel it was my fault. It felt like a hack solution and what bugged me the most was that I had no real understanding of the issue. There was no white-paper or release-notes that I was aware of that explained the issue I uncovered. I’m not sure I can even recreate the leak using anything but the complex environment of my game code. I’d love to make a lean code example of the issue without my entire game attached and submit it to Adobe and ask “why?”. I felt run down. A little defeated…
AND THEN… On a whim, I decided to test the code on a different machine. I should have done in the first place. It’s good practice to test the application in different environments with different browsers. I don’t know why I assumed my environment was error free. I was wrong.
I took the same exact game that had the leaky code and ran it in IE on a Windows XP 32 bit system. I was originally running on Windows 7 64bit using IE 32 bit. Using the same problematic version of my game but using the XP machine with latest flash installed the game had NO MEMORY LEAK. At that point I was mad. All this time I thought it was my fault. All this time I spent turning code on and off and locating obscure areas of code that my flash player decided it just didn’t like willy-nilly.
So now I go back and test variations of my game using past tests that failed before to see if they would pass this time on the different computer. Unluckily only some of the previous failed tests passed this time so I still had memory leaks that were my fault somewhere. OR the flash player on this other PC had a different kind of criteria for giving me faulty memory management. Either way I had to fix something because chances are I’m not the only one with the issue. However now I’m left second guessing whether or not the leaks are my fault or the player’s.
All I can do now is do further tests and isolate the areas of code that cause the game to break. Even if it’s a dumb flash bug and not my fault I still have to adapt since no amount of yelling at Adobe is going to fix this issue right this second.
The plus side to all of this testing is that it’s giving me a good understanding of how much memory certain features use. This will help me determine where I need to optimize the game to make it run smoother.
UPDATE: The saga continues… Read Part 3.
Pingback: Tell Me Where It Hurts Part 1: For the Horde