Context memory leak

hgray's Avatar

hgray

27 Jun, 2013 09:49 PM

RL 1.5.2

I've been pulling my hair out trying to resolve an issue with a memory leak. It occurs when I try to load a RL swf into another RL swf. At first I thought it was a lot of context mappings that I didn't unmap during shutdown. I then decided to simplify the set up for testing.

What I have now is a simple parent SWF which uses a Greensock SWFLoader to load a child SWF. I've also tried using a Loader to do the same thing. Whichever one, I've made sure to clean up any event listeners on completion. The child extends Sprite.

I'm using Adobe Scout to view the memory usage.

If my child is loaded as just a Sprite, when I release it, it returns all the memory. If I create a variable to hold a context, even if I don't instantiate it, I'm losing around 400-500k every time I load an unload the child.
private var myContext:Context;
I'm not even instantiating it, just having that definition present will do it.

Then I tried instantiating the context (just the default one, no mappings of any kind). My parent will then call to dispose the child which calls myContext.shutDown() (I know there's no need to since I have no mappings), listens for the shutdown_complete, removes the listener, and sets context=null. I still lose the same 400-500.

I've tried things like System.gc() to force the garbage collection, and I've also used Scout's force garbage collection feature. Either way, some of the memory is not released by the unload process.

I found a similar topic here which seems unresolved: http://stackoverflow.com/questions/13972535/why-does-context-become-a-gcroot

Does anyone have any ideas?

Thanks

  1. Support Staff 1 Posted by Shaun Smith on 27 Jun, 2013 10:08 PM

    Shaun Smith's Avatar

    Hi. If you attach a sample project I'll take a look (I haven't used Greensock SWFLoader).

    On 27 Jun 2013, at 22:50, "hgray" <[email blocked]> wrote:

  2. 2 Posted by hgray on 28 Jun, 2013 03:38 AM

    hgray's Avatar

    Thanks for the quick response. I've attached my simple test files.

    I have set up 4 tests. All 4 implement the same thing: they extend Sprite and have linkages to the two SWCs in the /libs folder, and all four contain the import for the RL context. Two were made in Flash and two were made in FlashBuilder.

    To test, run the bin-debug/Parent.html. You'll see four squares. Click on each while running a memory test (like Scout) to see what happens. Click the color a second time to unload the file (do this before loading the next file).

    Green: A FlashBuilder file, does not define the context var.
    Blue: Same as above. The only difference is that I have defined a var for a context. Note that it is not implemented, just defined.
    Red: A Flash file, no context var
    Yellow: Same as above with the var defined

    Findings: Green, Red, Yellow all load and unload the file with no perceptible memory leak. The blue one (FlashBuilder built, contains the var) loses 400-500k each cycle of the load/unload. Odd, right?

    I've included the source for everything. Let me know how it goes.

  3. Support Staff 3 Posted by creynders on 28 Jun, 2013 05:53 AM

    creynders's Avatar

    Have you tried this with a release version in the normal flash-player?
    I remember another post from someone having the same problem, but
    apparently it had to do with the debug release/player.

  4. Support Staff 4 Posted by Shaun Smith on 28 Jun, 2013 09:32 AM

    Shaun Smith's Avatar

    Thanks for attaching those samples. I'm at work today, but I'll dig in later and let you know what I find. Please note that I don't own a copy of the Flash IDE, so I can't test out the FLAs.

  5. 5 Posted by hgray on 28 Jun, 2013 03:33 PM

    hgray's Avatar

    Thanks creynders, I have not, that's a great suggestion. Although it is weird that the Flash generated files don't exhibit the same issue.

    Shaun, thanks very much! The FLAs are just simple containers. Each has a single square MovieClip on the stage which acts as a button. All of the code is in the document Class file.

  6. 6 Posted by hgray on 28 Jun, 2013 03:34 PM

    hgray's Avatar

    To clarify my testing, I've been clicking the same color 5-10 times to load and unload the same file several times in a row. With the blue one, what I see is a general stair stepping in Scout where each load is higher than the previous and each unload is not as low as the previous.

  7. Support Staff 7 Posted by Shaun Smith on 29 Jun, 2013 12:29 PM

    Shaun Smith's Avatar

    Hiya. So, I've taken a quick look at memory usage with Scout. I haven't looked at your source yet, or compiled things myself - I simply opened Parent.html in two different browsers (one with the Release Player and another with the Debug Player) while running Scout.

    Although it is weird that the Flash generated files don't exhibit the same issue.

    If you take a look at the size of the SWFs you can tell that the ones built with FB have been compiled as Debug SWFs (containing debug information and not optimised):

    fb_minigame_context.swf (29,101 bytes)
    FLA_minigame_context.swf (15,055 bytes)

    When benchmarking or analysing Flash content it is important to do so using SWFs compiled for Release running inside a Release version of the Flash Player. Debug SWFs running in a Debug Player provide completely different (and misleading) results.

    It's also important to distinguish between Current Total Memory and Used Memory.

    Here's my setup:

    1. Chrome with its built-in Release Player plugin
    2. Firefox with a Debug Player

    In Chrome the memory usage is exactly as I'd expect:

    It starts off, on frame 1, like so: 4,456 KB (total), 3,950 KB (used). This is basic player overhead and even an empty SWF reserves a certain amount of memory from the get-go. At this point we have 2530 objects living in the VM.

    Then I go completely mental and click load/unload on all the squares as fast as I can (616 times) and the memory gets as high as: 9,004 KB (total), 5,918 KB (used). Now we have 5918 objects floating about (many eligible for GC).

    A couple more clicks and GC kicks in and memory drops to: 5,332 KB (total), 3,220 KB (used), with 1800 objects remaining.

    You should notice that the used memory has dropped even lower than it was on Frame 1, and there are fewer objects!

    This looks completely normal to me, and is what I'd expect. GC only runs when it needs to in the Release player (you can only force it in the Debug Player). The memory graph looks like a saw tooth - it grows and grows as the SWFs are loaded, and then drops right back down when GC runs. We're interested in Used Memory; Total memory shows how much memory has been assigned to the player, not how much it is actually using.

    The Flash Player has a fairly complex memory management scheme - it has to balance memory usage against the performance impact of requesting new blocks of memory from the Operating System, and the cost of its "pause the world" Garbage Collection routine (which locks up the Player while it runs). Also, it is cheaper to hold on to freed blocks of memory than to release them and request them again later.

    So, that's the Release Player running Debug SWFs in Chrome. Now for the Debug Player running Debug SWFs in Firefox...

    Frame 1: 6,700 KB (total), 6,143 KB (used), 4291 objects. Straight off the bat we can see that more memory has been allocated, more memory is used, and more objects are alive.

    After going somewhat rampant: 7,284 KB (total), 6,725 KB (used) and 4833 objects. So, memory usage has gone up a bit, but objects are also being released more often.

    A couple more clicks we get: 10,572 KB (total), 8,648 KB (used) and 5800 objects.

    A few more clicks: 12,364 KB (total), 10,456 KB (used) and 6996 objects.

    So, what we're seeing here is that, even though you're forcing GC, memory isn't really being released for Debugs SWFs in a Debug player. Memory usage keeps growing and objects are not as aggressively pruned.

    In summary: Make sure to measure in an environment that matches deployment (i.e. Release SWFs in a Release Player).

    Debug SWFs contain unoptimised bytecode and a lot of debug information (line numbers, trace statements etc), and the Debug Player deals with memory completely differently to the Release Player.

    For more accurate measurements you should re-compile the FB SWFs as Release builds.

    I also haven't touched on how loading external SWFs affects memory usage; that's another topic for another time!

    I hope this has been helpful, and that you can see that RL does not leak memory.

  8. 8 Posted by hgray on 01 Jul, 2013 04:49 PM

    hgray's Avatar

    Very well spotted, and perfectly explained. It hadn't occurred to me that the debug builds from Flash Builder would be so messy with GC. I have built a release build from FB and confirmed that the memory usage is reduced as soon as I dispose of the swf.

    In our full production pipeline, we do use release builds for final output, but obviously in testing, the debug versions have been useful.

    Thanks again for the quick and thorough responses!

    Hardin

  9. Ondina D.F. closed this discussion on 09 Jul, 2013 01:44 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac