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.
November 3rd, 2007 at 1:24 am
Did you ever find a fix for this?
November 3rd, 2007 at 6:51 am
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
November 4th, 2007 at 5:11 pm
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.
November 8th, 2007 at 3:21 pm
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
}
November 13th, 2007 at 6:04 am
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.
November 17th, 2007 at 12:07 pm
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.
November 18th, 2007 at 9:41 am
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.
November 26th, 2007 at 3:30 am
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?
November 27th, 2007 at 8:55 am
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.
November 30th, 2007 at 11:38 am
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.
December 20th, 2007 at 4:05 pm
[...] version only). Previous to this method the only known way to force the garbage collection was the localConnection hack so this is good [...]
January 7th, 2008 at 9:57 am
[...] 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 [...]
February 9th, 2008 at 4:28 pm
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.
May 10th, 2008 at 7:32 pm
0e28503c2640
0e28503c26406d129e13
May 14th, 2008 at 11:04 am
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
May 14th, 2008 at 11:14 am
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
May 14th, 2008 at 11:58 am
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!
May 16th, 2008 at 11:13 pm
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!
June 21st, 2008 at 4:21 pm
sam, are you still checking this thread?
July 31st, 2008 at 12:07 am
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?
August 2nd, 2008 at 8:18 am
[...] http://www.dreaminginflash.com/2007/10/22/memory-leak-in-as3-loader-class/ [...]
August 14th, 2008 at 7:57 am
@Smith
Did you invoke dispose after Event.COMPLETE or unload() ?