views:

780

answers:

3

I'm working on reducing the memory requirements of my AS3 app. I understand that once there are no remaining references to an object, it is flagged as being a candidate for garbage collection.

Is it even worth it to try to remove references to Loaders that are no longer actively in use? My first thought is that it is not worth it.

Here's why: My Sprites need perpetual references to the Bitmaps they display (since the Sprites are always visible in my app). So, the Bitmaps cannot be garbage collected. The Bitmaps rely upon BitmapData objects for their data, so we can't get rid of them. (Up until this point it's all pretty straightforward).

Here's where I'm unsure of what's going on: Does a BitmapData have a reference to the data loaded by the Loader? In other words, is BitmapData essentially just a wrapper that has a reference to loader.content, or is the data copied from loader.content to BitmapData?

If a reference is maintained, then I don't get anything by garbage collecting my loaders...

Thoughts?

+1  A: 

Using AMF a bit with third party products has lead me to believe the Loader class attempts to instantiate a new class of the given content type (in this case it would be a Bitmap class instance). You are probably constructing a new BitmapData object from your Bitmap instance. From that I would assume that the Loader instance references the Bitmap instance, and in your case your code also references the Bitmap instance. Unless at some point you are calling BitmapData.clone().

There are also a couple of ways to force GC. http://stackoverflow.com/questions/192373/force-garbage-collection-in-as3

You may find it useful to attach some arbitrarily large object to something, then force the GC to see if that thing is getting cleaned up or floating around. If you are using Windows something like procmon (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) is more helpful than task manager for doing this kind of external inspection.

This of course is a bit trial and error but for lack of something like Visual VM (https://visualvm.dev.java.net/) we are kind of screwed in the Flash world.

Jotham
Thanks for your ideas, Jotham. I suppose this might be the best approach to solving this problem - a little bit of experimentation. Also, if it helps, the best thing I've found for tracking what's going on is an AS3 class by Julius Lomako. I've tweaked it a little so now it shows current/max mem usage, and current/ave fps, as well as graphs over time of these metrics. (Screenshot: http://www4.picturepush.com/photo/a/2474172/img/2474172.jpg) It runs within your app, of course, so it must be commented out for production builds. Email me at [email protected] if interested.
+1  A: 

It's a good question, but to the best of my knowledge, the answer is no -- neither Bitmap nor BitmapData objects possess references to the loaders that load them, so you can safely use them without concern for their preventing your Loaders from being collected.

If you want to make absolutely sure, though, use the clone() method of the BitmapData class:

clone()

Returns a new BitmapData object that is a clone of the original instance with an exact copy of the contained bitmap.

For example:

private function onCreationComplete():void
{
 var urlRequest:URLRequest = new URLRequest("MyPhoto.jpg");
 var loader:Loader = new Loader();
 loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loader_complete, false, 0, true);
 loader.load(urlRequest);
}

private function loader_complete(event:Event):void
{
 var img1:Image = new Image();
 img1.source = Bitmap(event.target.content);
 addChild(img1);

 var img2:Image = new Image();
 img2.source = new Bitmap(event.target.content.bitmapData.clone());
 addChild(img2);
}

Here, img1's source is a Bitmap cast explicitly from the BitmapData object returned by the loader. (If you examine the references in FlexBuilder, you'll see they are identical.) But img2's source is a clone -- new bunch of bytes, new object, new reference.

Hope that helps explain things. The more likely culprits responsible for keeping objects from being garbage collected, though, are usually event handlers. That's why I set the useWeakReference flag (see above) when setting up my listeners, pretty much exclusively, unless I have good reason not to:

useWeakReference:Boolean (default = false) — Determines whether the reference to the listener is strong or weak. A strong reference (the default) prevents your listener from being garbage-collected. A weak reference does not.

Christian Nunciato
Thanks for your thoughts, Christian. I still find it hard to believe that BitmapData duplicates the contents of the Loader, as this would (in most cases) be a huge waste of resources (both processor and memory). Also, clone()ing the BitmapData objects so I can remove the Loaders is sort of like trading some 'processor' for 'memory' in the optimization game - I'm not sure I'm this desperate yet, but it's an interesting thought indeed. Thanks for your insights!
Right -- well, in my img1 example above, the BitmapData object is not duplicated -- it's the same object. In img2, I explicitly clone the bytes to demonstrate how you'd do that, as there are times when you might want to. Either way, though, you're in the clear with respect to concern about references to the Loader. Good luck!
Christian Nunciato
A: 

you may set a variable in the complete listener that stores the bitmap and then destroy the object later

public function COMPLETEListener(e:Event){ myBitmap = e.target.loader.content; }

public function destroy(){ if(myBitmap is Bitmap){ myBitmap.bitmapData.dispose(); } }

works fine for me load some big image and see the difference in the taskmanager

coder