I'm having some trouble with memory management in a flash app. Memory usage grows quite a bit, and I've tracked it down to the way I load assets.
I embed several raster images in a class Embedded, like this
[Embed(source="/home/gabriel/text_hard.jpg")]
public static var ASSET_text_hard_DOT_jpg : Class;
I then instance the assets this way
var pClass : Class = Embedded[sResource] as Class;
return new pClass() as Bitmap;
At this point, memory usage goes up, which is perfectly normal. However, nulling all the references to the object doesn't free the memory.
Based on this behavior, looks like the flash player is creating an instance of the class the first time I request it, but never ever releases it - not without references, calling System.gc(), doing the double LocalConnection trick, or calling dispose() on the BitmapData objects.
Of course, this is very undesirable - memory usage would grow until everything in the SWFs is instanced, regardless of whether I stopped using some asset long ago.
Is my analysis correct? Can anything be done to fix this?
Make sure you run your tests again in the non-debug player. Debug player doesn't always reclaim all the memory properly when releasing assets.
Also, because you're using an Embedded rather than loaded asset, the actual data might not ever be released. As it's part of your SWF, I'd say you could reasonably expect it to be in memory for the lifetime of your SWF.
Why do you want to use this ???
var pClass : Class = Embedded[sResource] as Class;
return new pClass() as Bitmap;
Sometimes dynamically resource assignment is buggy and fails to be freed up. I had similar problems before with flash player and flex, for ex. loading and unloading the same external swf... the memory was increasing constantly with the size of the loaded swf without going down even if I was calling the system.gc(); after unloading the swf.
So my suggestion is to skip this approach and use the first case you have described.
UPDATE 1
<?xml version="1.0" encoding="utf-8"?>
<s:Application
xmlns:fx = "http://ns.adobe.com/mxml/2009"
xmlns:s = "library://ns.adobe.com/flex/spark"
xmlns:mx = "library://ns.adobe.com/flex/mx"
creationComplete = "creationComplete()">
<fx:Script>
<![CDATA[
[Embed(source="/assets/logo1w.png")]
private static var asset1:Class;
[Embed(source="/assets/060110sinkhole.jpg")]
private static var asset2:Class;
private static var _dict:Dictionary = new Dictionary();
private static function initDictionary():void
{
_dict["/assets/logo1w.png"] = asset1;
_dict["/assets/060110sinkhole.jpg"] = asset2;
}
public static function getAssetClass(assetPath:String):Class
{
// if the asset is already in the dictionary then just return it
if(_dict[assetPath] != null)
{
return _dict[assetPath] as Class;
}
return null;
}
private function creationComplete():void
{
initDictionary();
var asset1:Class = getAssetClass("/assets/logo1w.png");
var asset2:Class = getAssetClass("/assets/060110sinkhole.jpg");
var asset3:Class = getAssetClass("/assets/logo1w.png");
var asset4:Class = getAssetClass("/assets/060110sinkhole.jpg");
var asset5:Class = getAssetClass("/assets/logo1w.png");
}
]]>
</fx:Script>
At this point, memory usage goes up,
which is perfectly normal. However,
nulling all the references to the
object doesn't free the memory.
That's also perfectly normal. It's rare for any system to guarantee that the moment you stop referencing an object in the code is the same moment that the memory for it is returned to the operating system. That's exactly why methods like System.gc() are there, to allow you to force a clean-up when you need one. Usually the application may implement some sort of pooling to keep around objects and memory for efficiency purposes (as memory allocation is typically slow). And even if the application does return the memory to the operating system, the OS might still consider it as assigned to the application for a while, in case the app needs to request some more shortly afterwards.
You only need to worry if that freed memory is not getting reused. For example, you should find that if you create an object, free it, and repeat this process, memory usage should not grow linearly with the number of objects you create, as the memory for previously freed objects gets reallocated into the new ones. If you can confirm that does not happen, edit your question to say so. :)
It turns out I was keeping references to the objects that didn't unload. Very tricky ones. The GC does work correctly in all the cases I described, which I suspected may have been different.
More precisely, loading a SWF, instancing lots of classes defined in it, adding them to the display list, manipulating them, and then removing all references and unloading the SWF leaves me with almost exactly the same memory I started with.
Related
I suspect a problem with an old version of the ObjectBuilder which once was part of the WCSF Extension project and meanwhile moved into Unity. I am not sure whether I am on the right way or not so I hope someone out there has more competent thread-safety skills to explain whether this could be an issue or not.
I use this (outdated) ObjectBuilder implementation in an ASP.Net WCSF web app and rarely I can see in the logs that the ObjectBuilder is complaining that a particular property of a class cannot be injected for some reason, the problem is always that this property should never been injected at all. Property and class are changing constantly. I traced the code down to a method where a dictionary is used to hold the information whether a property is handled by the ObjectBuilder or not.
My question basically comes down to: Is there a thread-safety issue in the following code which could cause the ObjectBuilder to get inconsistent data from its dictionary?
The class which holds this code (ReflectionStrategy.cs) is created as Singleton, so all requests to my web application use this class to create its view/page objects. Its dictionary is a private field, only used in this method and declared like that:
private Dictionary<int, bool> _memberRequiresProcessingCache = new Dictionary<int, bool>();
private bool InnerMemberRequiresProcessing(IReflectionMemberInfo<TMemberInfo> member)
{
bool requires;
lock (_readLockerMrp)
{
if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo.GetHashCode(), out requires))
{
lock (_writeLockerMrp)
{
if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo.GetHashCode(), out requires))
{
requires = MemberRequiresProcessing(member);
_memberRequiresProcessingCache.Add(member.MemberInfo.GetHashCode(), requires);
}
}
}
}
return requires;
}
This code above is not the latest version you can find on Codeplex but I still want to know whether it might be the cause of my ObjectBuilder exceptions. While we speak I work on an update to get this old code replaced by the latest version. This is the latest implementation, unfortunately I cannot find any information why it has been changed. Might be for a bug, might be for performance...
private bool InnerMemberRequiresProcessing(IReflectionMemberInfo<TMemberInfo> member)
{
bool requires;
if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo, out requires))
{
lock (_writeLockerMrp)
{
if (!_memberRequiresProcessingCache.TryGetValue(member.MemberInfo, out requires))
{
Dictionary<TMemberInfo, bool> tempMemberRequiresProcessingCache =
new Dictionary<TMemberInfo, bool>(_memberRequiresProcessingCache);
requires = MemberRequiresProcessing(member);
tempMemberRequiresProcessingCache.Add(member.MemberInfo, requires);
_memberRequiresProcessingCache = tempMemberRequiresProcessingCache;
}
}
}
return requires;
}
The use of the hash code looks problematic if you run a very large number of classes / members, as can happen with the singleton approach you mentioned.
The double lock was totally odd in the old one (Only one thread goes into the whole section in all cases). Note that locking as the first thing certainly hurts performance. It is a trade of, notice that instead they create a copy to avoid modifying the list as it is being read.
When flex array collection is handled with large amount of data for example 2,00,000 new referenced objects the memory in flex client browser shoots up 20MB. This excess 20MB is independent of the variables defined in the object. An detailed example is illustrated below.
var list:ArrayCollection = new ArrayCollection;
for(var i:int = 0;i<200000;i++)
{
var obj:Object = new Object;
list.add(obj);
}
On executing the above code there was 20MB increase in flex client browser memory. For a different scenario i tried adding an action script object into the array collection. The action script object is defined below.
public class Sample
{
public var id:int;
public var age:int;
public Sample()
{
}
}
On adding 200000 Sample class into a array collection there was still 20MB memory leak.
var list:ArrayCollection = new ArrayCollection;
for(var i:int = 0;i<200000;i++)
{
var obj:Sample = new Sample;
obj.id= i;
onj.age = 20;
list.add(obj);
}
I even tried adding the Sample Objects into flex arrayList and array but the problem still persists. Can someone explain on where this excess memory is consumed by flex?
Requesting memory to the OS is time consuming, so Flash player requests large chunks of memory (more than it really needs) in order to minimize the number of those requests.
I have no idea if the OS allocation time is a big deal anymore, we're talking on avg 1.5-2GHz Cpu's - even mobile. But Benoit is on the right track. Large chunks are reserved at a time to mainly avoid heap fragmentation. If memory was requested in only size chunks it needs at a time, along with other IO requests, the system memory would become highly fragmented very quickly. When these fragments are returned to the OS space - unless the memory manager gets a request of the same size or smaller, it cannot reallocate this chunk - thereby making it lost to the visible pool. So to avoid this issue - Flash (and it's memory manager) requests 16Mb at a time.
In your case, it wouldn't matter if you created 1 object or 100,000. You'll still start with a minimum of 16Mb private memory (aka what you see in task manager).
The flash player allocation mechanism is based on the Mozilla MMgc.
You can read about it here: https://developer.mozilla.org/en-US/docs/MMgc
I have developed my first flex mobile application which is of TabbedViewNavigatorApplication. Application is working fine but when I test the application in "profile handler", memory usage goes on increasing as I navigate through the application. When I came to know that, I have to remove all the added eventlisteners and I have to nullify the objects which are no longer needed. When I switch between tabs , tabs are initialising again and again.
I dont know where can I remove the eventlisteners. I mean, I have written functions for each eventlisteners . Do I need to remove eventlistener when control goes to the function definition.
I have written sample code
var more:Image = new Image();
more.width = 70;
more.height=29;
more.x=10;
more.y=276;
more.source = "Assets/more button.png";
more.addEventListener(MouseEvent.CLICK, MORE_clickHandler);
mainGroup.addElement(more);
private function MORE_clickHandler(e:MouseEvent):void {
// Do I need to remove the eventlistener here
}
Also , do I need to explicitly nullify the object of Image class which I created or garbage collector will handle it. If I need to explicitly nullify it, where to do this.
Thanks
Garbage collection is an important part of any language, especially on mobile. Since mobile devices are a lot more limited than say our desktop counterparts, you need to be very careful what is being created/stored to memory. My motto is, if you don't see it, you shouldn't keep it. You can destroy views but keep their state using a view model.
To remove a view, you need to first remove it from the display list (removeElement(yourObject)), remove all event listeners, and nullify any referencing variable. If any variable still has a reference to it, it won't get garbage collected.
I recommend you read up a bit more on garbage collection as well as some neat tricks like pooling and virtualization (item renderers in a list).
You can setup an event listerener with a weak reference.
This implies that when the only reference to your object is the listener, the object itself can still be garbage collected and the listener will not keep it in memory.
The following will do the trick :
more.addEventListener(MouseEvent.CLICK, MORE_clickHandler,false, 0, true);
Another option would be to subclass the image class and let it implement an IDisposable interface, which would force you to implement a dispose() method.
Some handy resources:
http://www.intriguemedia.net/2007/09/24/when-to-use-weak-references
http://gskinner.com/blog/archives/2006/07/as3_weakly_refe.html
cheers
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?
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. 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.
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.
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
I have a pretty big Flex & Papervision3D application that creates and destroys objects continually. It also loads and unloads SWF resource files too. While it's running the SWF slowly consumes memory til about 2GB when it croaks the player. Obviously I am pretty sure I let go of reference to instances I no longer want with expectation the GC will do its job. But I am having a heck of a time figuring out where the problem lies.
I've tried using the profiler and its options for capturing memory snapshots, etc - but my problem remains evasive. I think there are known problems using debug Flash player also? But I get no joy using the release version either.
How do you go about tracking down memory leak problems using FLEX/AS3 ? What are some strategies, tricks, or tools you have used to locate consumption
I usually implement a cleanup method in every class I make (since AS doesn't have destructors). The main problem I've noticed with the GC is with event listeners. Additional to what dirkgently said, also try to avoid anonymous listener functions (as you can't explicitly remove them). Here are a few links you may find useful:
Understanding Memory Leaks in ActionScript
Garbage Collection with Flex and Adobe Air
I stumbled across something explaining how to use Flex Profiler in Flex Builder and it was a HUGE help to me in debugging memory leaks. I would definitely suggest trying it out. It's very easy to use. Some things I found when profiling my applications:
Avoid using collections (at least LARGE collections) as properties of Value Objects. I had several types of Value Object Classes in my Cairngorm application, and each had a "children" property which was an ArrayCollection, and was used for filtering. When profiling, I found that these were one of my biggest memory eaters, so I changed my application to instead store the "parentId" as an int and use this for filtering. The memory used was cut drastically. Something like this:
Old way:
public class Owner1
{
public var id:int;
public var label:String;
public var children:ArrayCollection; // Stores any number of Owner2 Objects
}
public class Owner2
{
public var id:int;
public var label:String;
public var children:ArrayCollection; // Stores any number of Owner3 Objects
}
public class Owner3
{
public var id:int;
public var label:String;
}
New Way:
public class Owner1
{
public var id:int;
public var label:String;
}
public class Owner2
{
public var id:int;
public var label:String;
public var parentId:int; // Refers to id of Owner1 Object
}
public class Owner3
{
public var id:int;
public var label:String;
public var parentId:int; // Refers to id of Owner2 Object
}
I would also suggest removing event listeners when they are no longer needed.
because of issues like this I've developed a open source library that helps monitor all the events your running at any given time. its really easy to implement and i've re-factored projects in 10-15 minutes converting them to use the EventController i've developed.
basically for your scenario i would run through all the events and replace them from:
obj.addEventListener(...);
to :
EC.add(obj,...);
the rest is the same what that would do is register the event and make it crazy easy to see all your events at any point you want using the EC.log();
all the details and documentation are on my site i would love to know if this helps you and if you start working with it. if you have any feedback good or bad please feel free to post it up and i would look into it!
the site is:
http://fla.as/ec/
If your memory leak grows exponentially, it probably means GC is failing to do its job. Take a look at your code and see wherever you can decrease your objects' reference counts (by setting them to null). Make event-handlers weak. And re-profile.