Memory Leak in AS3 Loader Class

Today I came across a nasty memory leak in the Loader Class.

I was writting a simple screensaver class that loads external images from the hdd and displays them. Sounds simple? It is. The problem was that everytime I loaded an image, the system memory would go up. I started by checking my eventListeners. They where all weak referenced. I went through the code looking for places where I could be keeping a reference and hence preventing the GC to collect it, but I couldn't find any.

There is something keeping the GC from removing the old images from memory...

Everytime the Loader calls the load() method the image is read into memory and stays there. I tried calling the unload() method but that doesn't help.

Then, how can one remove the loaded image from memory? If you know please let me know...

The only workaround I came up with was gskinners unsupported method to force the GC

This works great, but I would like to know what's keeping the GC from removing the previous images from memory...
Let me know if you have an answer.

Example showing the memory leak

22 Responses to “Memory Leak in AS3 Loader Class”

  1. rob Says:

    Did you ever find a fix for this?

  2. Tiago Bilou Says:

    I still couldn’t find a reason why the GB can not remove the previous images. However if you use gskinner’s unsupported method o force the GC it works

  3. Daniel Says:

    I couldn’t understand some parts of this article Memory Leak in AS3 Loader Class, but I guess I just need to check some more resources regarding this, because it sounds interesting.

  4. a_[w] Says:

    import flash.display.*;
    var loader:Loader = new Loader();
    ……
    var li:LoaderInfo = loader.contentLoaderInfo;
    if(li.childAllowsParent && li.content is Bitmap){
    (li.content as Bitmap).bitmapData.dispose(); // remove bitmap from memory
    }

  5. Idoru Says:

    To: a_[w]
    Well that works, but if you move to video objects you’ll find the same problem.
    Talking with Richard Galvan, from Adobe, he explained that this is a known bug that will be fixed soon when the the garbage collector is made to be more active.
    Also the localConnection work.around will cease to work then.

  6. Phill Says:

    Are you sure it is a leak? It’s obviously eligible for collection (as the localconnection hack forces the collector to collect everything which doesn’t have a strong reference to it). Just because something is eligible doesn’t mean Flash will free the memory associated with it straight away. I’m not sure of the exact heuristics used but it may well not free that memory until it really needs it. I think if it was leaking the localconnection hack wouldn’t clear the memory as it wouldn’t think it was eligible.

  7. Idoru Says:

    Hi Phill,
    Well the problem is that the mark and sweep might not run for a very long period of time, and thus even if you need the extra memory you won’t have it, grant skinner described it quite accurately, and also as i said talking to adobe people they confirmed that the GC isn’t yet that optimized.

  8. Ncatdesigner Says:

    Hi everybody,

    I’m using a banner that loads various jpg, first a b&w jpg for a fast preview and then the swf or jpg version (only jpg for the moment) when I’ve loaded more than 20 images aprox. the web browser decrease the speed of the processor.

    Can I use the method above??

    I’ve used kind of
    import flash.display.*;
    var loader:Loader = new Loader();
    ……
    var li:LoaderInfo = loader.contentLoaderInfo;
    if(li.childAllowsParent && li.content is Bitmap){
    (li.content as Bitmap).bitmapData.dispose(); // remove bitmap from memory
    }

    not working…

    Advise! Newbie question:
    Why many codes use foo, what’s foo?

  9. Tiago Bilou Says:

    Hello Ncatdesigner

    foo is just a name coders like to use. Instead of foo you can use any name you want.

    As for the the code, if you want to use the hack to call the GC make sure you clean up any references (events, addChilds, …)
    Then just place the lines to force the GC to run inside your IF statement. That should do the trick.

  10. Guillaume Lecanu Says:

    Hi,

    I have detected the same problem with the Image() object.
    I have reported it : http://bugs.adobe.com/jira/browse/ASC-3030

    But no news, I think people need to vote for this bug ticket to permit to solve it more quickly.

  11. Dreaming in Flash » Blog Archive » Another Way to Force the Garbage Collection Says:

    [...] version only). Previous to this method the only known way to force the garbage collection was the localConnection hack so this is good [...]

  12. Dreaming in Flash » Blog Archive » Memory Leak Unit Test Says:

    [...] our resources from memory, which makes it hard to test something like this. But there are two ways ([2] and [3]) to force the GC to run so we can use that to test that something that should have been [...]

  13. Peter Says:

    Just on the foo question…
    In an old and famous WWII movie (can’t remember the title) some guys always use the expression FUBAR and you find out at the end it stands for F@cked Up Beyond All Recognition.
    That’s the origin of naming sample variables foo and bar.

  14. 0e28503c2640 Says:

    0e28503c2640

    0e28503c26406d129e13

  15. Samuel Agesilas Says:

    Hi Guys,

    I was googling some info for an AS3 concern and I came across this post. I understand everyone’s concern here but I can assure you guys that this is NOT a memory leak. Generally speaking memory leaks are caused when a program allocates memory but fails to de-allocated it correctly( The famed dealloc method in C/C++). AS3 developers for the most part can’t cause memory leaks directly because of the GC, that in essence is what the GC is for, to prevent these kinds of things(there are exceptions though but they are rare). If there is a memory leak in the VM (like the one cause by the XML object several years back) is mostly likely due to faulty code in the VM. Now having said this I can assure that in your case this is not a memory leak. You see the new VM uses a much more advanced and performant GC that uses the much safer and accurate mark and sweep method. Mark and sweep is the same GC strategy that the Java VM uses as well however like the Java VM the Flash VM is also slow when using Mark and sweep, which implies that code must be written better or it will hiccup when the GC kicks in. I downloaded your code and analysed it and found it to be well written, except for the gskinner code which in this case you don’t really need. Why? well because the GC just hasn’t received an opportunity to removing that object yet. This is fairly common in systems that use VM’s and GC’s. I obviously don’t work for Adobe, so I don’t have access to the C code of the Flash Player, but I’ve worked on VM’s before and a lot of them employ a memory threshold strategy, that is the GC will only start actively or aggressively working if a certain memory threshold has been met. Example, total system memory is 1024K, your running app gets an allocation of 256K but the GC doesn’t kick in until memory consumption tops 90k. Like I mentioned earlier I’m not sure if this is the case with the Flash VM but I wouldn’t be surprised if it was employed to keep things moving quickly and if this is indeed the case your code probably didn’t hit that threshold. Whatever the case be, rest assured that nothing is wrong with your code and that the behaviour you are witnessing is normal. The AS3 GC is much, MUCH better than it’s predecessors and I know for a fact that the Flash Player Engineering Team where very much aware of the shortcomings of the previous implementation. I’ll probably post a much more in-depth post on memory access in the Flash VM but for now I hope this helps. Email me if you need anything!

    Cheers mate!
    Sam

  16. Samuel Agesilas Says:

    Oh, I forgot to mention, that using statements like dispose() or delete does NOT work like C’s dealloc statement. Meaning that all those statements do is mark a particular object for the GC to delete them(if it can) when the GC is ready to delete them. They do not necessarily delete the object immediately.

    :)
    Cheers,
    Sam

  17. Idoru Says:

    Wow sam, thanks for the great ‘post’ :)
    Right you are on all the stuff you said, altough speaking with Richard Galvan and Tinic, they acknowledged that this was indeed a Leak in the VM at the time of writing the article, it has been fixed in the latest versions.
    But great post man, and thx!

  18. Samuel Agesilas Says:

    Awesome!! Good thing the Flash Player team confirmed and fixed the bug. Memory Leaks are so difficult to fix but thanks to folks like yourself that bring these issue’s to light, really help the FP Team bang them out. Cheers!

  19. kglad Says:

    sam, are you still checking this thread?

  20. smith Says:

    Regarding the code:
    var li:LoaderInfo = loader.contentLoaderInfo;
    if(li.childAllowsParent && li.content is Bitmap){
    (li.content as Bitmap).bitmapData.dispose(); // remove bitmap from memory
    }

    when running Simulate Download in Flash IDE, got eeror:
    Error: Error #2099: The loading object is not sufficiently loaded to provide this information.
    at flash.display::LoaderInfo/get childAllowsParent()
    at com.cfour.app.afl.mural::PopupWindow/disposeImage()
    at com.cfour.app.afl.mural::PopupWindow/closeHandler()

    trace(li) got null.

    Why?

  21. Christopher’s Blog» Blog Archive » 两篇关于AS3内存泄漏的文章 Says:

    [...] http://www.dreaminginflash.com/2007/10/22/memory-leak-in-as3-loader-class/ [...]

  22. Shadow_SB Says:

    @Smith

    Did you invoke dispose after Event.COMPLETE or unload() ?

Leave a Reply