Flex 3 Memory leak issue - actionscript-3

We have a huge flex applications using multiple modules. There is a huge memory leak problem over prolonged usage of loading and unloading modules.
Based on all the search and different articles I understand that I need to clean up objects on unload, remove event listeners, stop timers and dispose any references.
I started this by picking up one component at a time within one of the module.
Here is how this is structured.
There is one parent application which loads a module, which has multiple views. The component is defined in mxml and is referenced in the mxml module in a view stack.
This mxml component is a VBox with event listeners added as-
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
paddingTop="10"
paddingLeft="10"
paddingBottom="10"
paddingRight="10"
creationComplete="onInit()"
show="onShow()"
resize="onResize(event)" ....
There are couple of properties that are binded from the parent container in mxml. Other than the above listeners there is also a private variable accessed from outside -
[Bindable]
private var _model:SModelLocator=SModelLocator.GetInstance();
On unload of the module I call a dispose function in this component as below-
public function dispose():void
{
this.removeEventListener(FlexEvent.CREATION_COMPLETE,onInit);
this.removeEventListener(FlexEvent.SHOW,onShow);
this.removeEventListener(ResizeEvent.RESIZE,onResize);
var arr:Array = this.getChildren();
for(var i:int = 0; i<arr.length;i++)
delete arr[i];
this.removeAllChildren();
_model = null;
//Properties that are binded from the parent container
Property1 = null;
Property2 = null;
this.deleteReferenceOnParentDocument(this.parentDocument as IFlexDisplayObject);
}
Now when I run profiler and switch between modules number of instances of this component still continues to grow. I clicked on GC Collect on profiler and still the instances stay.
On the parent container which is the module mxml, I also tried writing the following lines upon unload of module-
//function call to invoke dispose as above
component1.dispose();
component1 = null;
Please help. I am not sure what am I missing here, or even if this is the right approach.
Thanks.

This will not solve your problem but I hope it helps.
First and foremost you are not getting anywhere just by looking and refactoring code. You need hardcore data that proves that you have a leak, which then will tell you what is leaking so you can fix it. From all the memory profilers I've used the FlashBuilder one is still the best, the IntelliJ one was not reliable a year and Adobe Scout only does performance analysis.
Start by your smallest modules and with the memory profiler open prove that opening and closing a module (preferably in isolation of the main rig) creates a leak. If that's the case I would start by removing ALL the code from the module, and testing it again, add part by part which will lead you to the lead eventually. You can use a best suspects search, where you first address event listeners, etc.
This article from Thomas Sugden is still the best I've read about flex memory profiling and you should read it from end to end if you haven't.
It worth your time to write tools that allow you to test your modules, who knows even automate the process that evaluates if there are leaks or not. This is important because sometimes there are leaks that will not be your fault, the Flex framework has a bunch of them that you just can't avoid.
Hope this helped.

You might want to try a different container. I've personally had performance issues with VBox. And as the pervious user said, Flex has a habit of waiting until memory reaches high levels before it performs a memory sweep.

Flash doesn't always initiate the memory sweeping method, but it only frees null pointers when you are taking up memory excessively, so do mind that hindrance.

Related

Detecting/recording AS3 "stop the world" GC pauses

Context: a large AS3 application that may be suffering from frequent but unpredictable "stop the world" garbage collection pauses. When one does strike it can take 30s or more to conclude.
This does not occur in testing, however it may in production.
Question: Is there any logging available from the Flash VM that might be used to detect and record such events? I am drawing on my experience with Java here. I have read widely on the functioning of the Flash GC machinery (reference-counting with mark/sweep), but I'm looking for some real telemetry from an application running in the wild as I understand that a mark/sweep GC event can "stop the world".
You are correct. The garbage collector pauses application execution.
The Flash Runtime garbage collector algorithm runs incrementally while marking memory in use. It pauses application execution when collecting unused portions of memory. The pause that occurs as the incremental collection cycle finishes can be longer than desired and can be observable or audible in some programs.
from reference
Check if garbage collector did run
As to my knowledge there is no direct way to know if GC ran. But it is possible to have a test function execute on ENTER_FRAME and check if the garbage has been collected since the last function call. Effectively since the last frame.
Through a Dictionary which can store weak referenced keys it is possible to see if an object has been collected. If this is the case garbage collection must have run. In the following class I create a new object, to later check if it has been collected.
package
{
import flash.display.Sprite;
import flash.utils.Dictionary;
public class GCTest
{
private static var dict:Dictionary = null;
public static function didGCRun():Boolean
{
if ( dict == null ) {
dict = new Dictionary(true);
}
var hasKeys:Boolean = false;
for ( var obj:* in dict ) {
hasKeys = true;
break;
}
if ( hasKeys ) {
return false;
}
else {
dict[new Sprite()] = null;
return true;
}
}
}
}
By checking on each frame you will know if gc stroke
addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(event:Event):void
{
var gcRan:Boolean = GCTest.didGCRun();
}
Memory usage
You can also monitor garbage collection by checking memory usage. The documentation advises to use System.freeMemory()
The amount of memory (in bytes) that is allocated to Adobe Flash Player or Adobe AIR and that is not in use. This unused portion of allocated memory (System.totalMemory) fluctuates as garbage collection takes place. Use this property to monitor garbage collection.
I would use this value in conjunction with System.totalMemoryNumber()
Validate execution times
In conjunction with the other methods it might be helpful to record the actual frame rate or the execution time of code blocks. This can be achieved by storing the programs "uptime" in a variable and comparing it at a later point.
Use getTimer()
For a Flash runtime processing ActionScript 3.0, this method returns the number of milliseconds that have elapsed since the Flash runtime virtual machine for ActionScript 3.0 (AVM2) started.
var startTime:int = getTimer();
// execution or frame change
var executionTime:int = getTimer() - startTime;
when used on each frame you can compare this to stage.frameRate and check for discrepancies.
Advise garbage collector to execute
A possibility to mitigate your pauses might be to advise the garbage collector to execute manually. System.pauseForGCIfCollectionImminent(imminence:Number = 0.75) will pause program execution if the actual imminence is higher than the arguments value.
Imminence is defined as how far through marking the collector believes it is, and therefore how close it is to triggering a collection pause. The imminence argument to this function is a threshold: the garbage collector will be invoked only if the actual imminence exceeds the threshold value. Otherwise, this call returns immediately without taking action.
By calling this function with a low imminence value, the application indicates that it is willing to accept that a relatively large amount of marking must be completed. A high imminence value, on the other hand, indicates that the application should be paused only if marking is nearly complete. Typically, pauses are longer in the former case than in the latter.
imminence:Number (default = 0.75) — A number between 0 and 1, where 0 means less imminent and 1 means most imminent. Values less than 0 default to 0.25. Values greater than 1.0 default to 1.0. NaN defaults to 0.75
from reference
Adobe Scout is a nice tool to profile AS3 projects.
You can use :
setInterval( function()
{
trace(System.totalMemory);
},1000);
whenever garbage collector works and it's busy the amount of memory changes a lot. if you see the memory changes and at the same time your program paused or has glitches so it has been caused by GC.
first of all, what is your production environment ?
flash player, AIR desktop, AIR mobile ?
Your app is supposed to perform computation heavy tasks ?
30+ seconds of garbage collecting seems huge, but if the pauses are indeed caused by the garbage collector, logging it will not help you much, except confirming your supposition.
The first thing I would do, is extensively test your app with telemetry
If you see any sign of abnormal activity of the GC (big red spikes, or a permanent gc noise that is more than a couple of percents on every frame), activate memory allocation telemetry and find/eliminate bottlenecks in memory instantiations. Just remember that even freed allocations have an impact on gc so use pooling, and be very strict on allocations that occur on every frames, even a few allocations will have a significant impact.
Beware that parsing big xml or json files is very heavy on allocations.
Once you have made sure that your application is using memory properly, check (or let your testers/beta testers/users check) if the problem is still here or if it's less frequent or even has disapeared.
If it does't work, you will have at least improved the performance and memory footprint of your app in the first place
Don't you have more information on the nature of the pause and have you considered other options than GC ? Maybe the probleme is not where you search it :
You can try catching and logging all errors with UncaughtErrorEvent (then use URLLoader to post the error stack to your error logging service). It could help you detect hard to reproduce errors in production, for instance:
stuck in a function: should throw a ScriptTimeoutError after 15 seconds (code #1502) which will open a popup in flash player debugger.
any other Error will interrupt the whole stack which may put your application in an unresponsive state. Maybe some long timeout is making it responsive again ?
BTW How do you know that you application is experiencing 30+ seconds freeze if you are not logging it and have never reproduced it ? If it is a bug reported by end users, try to get more informations (get their os, flash player version, pattern...) If it's frequent, you should be able to reproduce it.

Does a SpriteBatch instance need to call dispose() once it is no longer used?

According to this article, a SpriteBatch instance needs to call dispose() once it is no longer needed. However, as I examine some of libgdx's official examples like Pax Britannica and Super Jumper, I found out that they never call SpriteBatch.dispose(). Why is that?
SpriteBatch must always be disposed.
Internally, it creates and manages several Mesh objects. These objects allocate vertex/index arrays on the GPU. Those are only deallocated if you explicitly call Mesh#dispose(), which will be triggered by calling dispose() on your SpriteBatch object.
It will also, by default, create its own ShaderProgram. And similarly, would be leaked if you didn't call dispose().
If the demo's aren't doing this, perhaps it's time to send a pull request!
I think the given demo games try to keep things simple. They are supposed to show how the basic things in libgdx work in a minimalistic way and thus also abstract a little of some details. That's useful for beginners to not bloat up the examples with a lot of very specific code.
In a real world example I think SpriteBatch.dispose() has to be called in the dispose() method of the GameScreen in SuperJumper for example. And also GameScreen.dispose() has to be called when switching back to the MainMenuScreen, because this doesn't happen automatically as well.
When creating a Spritebatch like this new SpriteBatch(), it creates one internal Mesh. When not calling SpriteBatch.dispose() this one mesh would also not be disposed and thus SuperJumper has a memory leak there.
I've created games where I have multiple screens which all has their own SpriteBatch. I just removed all dispose() methods of the batches and for me, there's no effect of this. So keep in mind to check for this before releasing your product. Even if you can't feel any downside not to dispose batches, there's no reason not to dispose them. Just do it on the Screen implemententations dispose methos, takes about 1 nano second to do :)

AS3 memory leak

I've been working on a library, and have run into a problem with application memory.
I created a class called FileManager which allows the user to call a function called loadNewFiles - this function opens a multi-file selection dialog and stores each FileReferenceList in a vector. I can call the removeList function at any time and remove that list and clear any memory and listeners allocated to that list, so all's well there.
I created another class called UploadManager, which takes an array of FileReference objects and uploads them to a URL via the uploadFiles function. The memory leak appears to be here. When you call this function, it adds the appropriate event listeners and calls the upload function. If the upload fails or the upload is finished, it removes the listeners and clears the vector it has been waiting in.
after the upload manager finishes uploading the files, I call the removeFiles function in FileManager (which, remember, worked perfectly before) and... Nothing happens. The files are removed from both vectors, the listeners are removed from both files, but the memory stays allocated. This obviously has potential to cause problems along the road, as there's no limit to the number of files, uploads, etc. available through the library.
classes:
FileManager
UploadManager
Implementation
It sounds like from your example that the UploadManager still has a reference to the files either from the vector passed into uploadFiles, or some other object in the game still has a reference.
Also note, System.gc() only works on the debug version of the flash player.
So you can't depend on it for an architectural design choice. It works for unit testing memory intensive operations when you need to see the consumption of ActionScript memory "on demand".
In a production product, the ActionScript Virtual Machine is very active in detecting when and where to garbage collect. Most would say it happens right when you don't want it to.
Try profiling the application and looking at the "cumulative instances" vs. "instances", as well as the "cumulative memory" vs. "memory" for the objects in question (i.e. FileReference).
You can force garbage collection during runtime in the Profile View to get a realistic idea of how much memory is actually freed when garbage collection takes place in the Release version.

AS3 - when does the garbage collector run?

apologies if this is a dupe; i couldn't find it.
i've read and understood grant skinner's blog on the AS3 garbage collector -
http://www.adobe.ca/devnet/flashplayer/articles/garbage_collection.html ,
but my question isn't covered there.
here's my question.
suppose i've written some AS3 code like:
statementOne;
statementTwo;
is there any possibility that the garbage collector will run during or between my two statements, or does it only run after my "user" code has finished and returned control up to flash ?
we have an A-Star codeblock that's sometimes slow,
and i'd like to eliminate the GC as a potential culprit.
the codeblock is obviously more complex than my example above,
but it doesn't involve any events or other asynchronous stuff.
tia,
Orion
The garbage collector isn't threaded, so generally speaking it won't run while your code is running. There is one exceptional case where this isn't true, however.
The new keyword will invoke the garbage collector if it runs out of memory.
You can run this code to observe this behaviour:
var vec:Vector.<*> = new Vector.<*>(9001);
for (;;) {
vec[0] = new Vector.<*>(9001);
vec = vec[0];
}
Memory usage will quickly jump up to the maximum (1GB for me) then hold until the time cutoff.
There are many good answers here but I think a few subtleties have not been addressed.
The Flash player implements two kinds of garbage collection. One is reference counting, where Flash keeps a count of the incoming references to each object, and knows that when the count reaches zero the object can be freed. The second method is mark-sweep, where Flash occasionally searches for and deletes isolated groups of objects (where the objects refer to one another, but the group as a whole has no incoming references).
As a matter of specification either kind of garbage collection may occur at any time. The player makes no guarantee of when objects will be freed, and mark-sweeps may even be spread out over several frames. Further, there's no guarantee that the timing of GCs will stay the same between Flash player versions, or platforms, or even browsers. So in a way, it's not very useful to know anything about how GCs are triggered, as you have no way of knowing how widely applicable your knowledge is.
Previous point aside, generally speaking mark-sweeps are infrequent, and only triggered in certain circumstances. I know of certain player/OS configurations where a mark/sweep could be triggered every N seconds, or whenever the player exceeded P% of the total available memory, but this was a long time ago and the details will have changed. Reference-counting GCs, in contrast, can happen frequently - between frames, at least. I don't think I've seen them demonstrated to happen more frequently, but that doesn't mean it can't occur (at least in certain situations).
Finally, a word about your specific issue: in my experience it's very unlikely that the GC has anything to do with your performance problem. Reference-counted GC processing may well occur during your loops, but generally this is a good thing - this kind of collection is extremely fast, and keeps your memory usage manageable. The whole point of managing your references carefully is to ensure that this kind of GC happens in a timely manner.
On the other hand, if a mark/sweep occurs during your loops, that would certainly affect your performance. But this is relatively hard to mistake and easy to test. If you're testing on a PC and your application doesn't regularly climb into the hundreds of MBs of memory usage (test with System.totalMemory), you're probably not getting any mark/sweeps at all. If you do have them, it should be easy to verify that the associated pauses are large, infrequent, and always accompanied by a big drop in memory usage. If those things aren't true, you can disregard the idea that GC is part of your problems.
To my knowledge, this is not documented. I have a feeling the GC won't run while your code is being executed (that is, while your code is on the execution stack; each frame, the player creates a new stack for use code). Obviously, this comes from observation and my own experience with Flash, so I wouldn't say this is 100% accurate. Hopefully, it's an educated guess.
Here's a simple test that seems to show that the above is true:
package {
import flash.display.Sprite;
import flash.net.FileReference;
import flash.system.System;
import flash.utils.Dictionary;
import flash.utils.setTimeout;
public class test extends Sprite
{
private var _dict:Dictionary = new Dictionary(true);
public function test()
{
testGC();
setTimeout(function():void {
traceCount();
},2000);
}
private function testGC():void {
var fileRef:FileReference;
for(var i:int = 0; i < 100; i++) {
fileRef = new FileReference();
_dict[fileRef] = true;
traceCount();
System.gc();
}
}
private function traceCount():void {
var count:int = 0;
for(var i:* in _dict) {
count++;
}
trace(count);
}
}
}
The GC seems to be particularly greedy when there are FileReference objects involved (again, this is from my experience; this isn't documented as far as I know).
Now, if you run the above code, even calling explicitly System.gc(), the objects are not collected while your function is on the stack: you can see they're still alive looking at the count of the dictionary (which is set to use weak references for obvious reasons).
When this count is traced again, in a different execution stack (caused by the asynchronous call to setTimeout), all objects have been freed.
So, I'd say it seems the GC is not the culprit of the poor performance in your case. Again, this is a mere observation and the fact that the GC didn't run while executing user code in this test doesn't mean it never will. Likely, it won't, but since this isn't documented, there's no way to know for sure, I'm afraid. I hope this helps.
GC will not run between two statements that are on the same stack / same frame like you have in your example. Memory will be freed prior to the execution of the next frame. This is how most modern VM environments work.
You can't determine when GC will run. If you are trying to stop something from being GC'd, keep a reference to it somewhere.
According to this Tom from Gabob, large enough orphaned hierarchies do not get garbage collected.

AS3 Memory management when instantiating extended classes

I'm developing an AS3 application which has some memory leaks I can't find, so I'd like to ask some newbie questions about memory management.
Imagine I have a class named BaseClass, and some classes that extend this one, such as ClassA, ClassB, etc.
I declare a variable:
myBaseClass:BaseClass = new ClassA();
After a while, I use it to instantiate a new object:
myBaseClass = new ClassB();
some time after
myBaseClass = new ClassC();
and the same thing keeps happening every x millis, triggered by a timer.
Is there any memory problem here? Are the unused instances correctly deleted by the garbage collector?
Thanks!
Assuming you have no other references to the instance (or, possibly, its contents), the garbage collector will clean them up. However, the time before cleanup is, as far as I know, indeterminate (there might be some hard timeline in use, but I've never seen it documented). If you're creating a huge number of instances, you might use up a lot of memory before the first ever gets cleaned up.
There is an AS call (the name of which escapes me at the moment) to force a GC run, but it shouldn't normally be necessary. If you find it necessary, you almost certainly need to rethink how your application works.
If myBaseClass is the only stored reference to
new ClassA()
and you assign something else to myBaseClass
new ClassB()
then there will be no reference pointing to ClassA and the garbage collector should find it when it runs.
However, if you give myBaseClass to a library or class that stores its own reference to that object, when you reassign myBaseClass there will still be a reference pointing to the ClassA and the garbage collector will not clean it up, creating a memory leak. Normally a well written library will provide you with a way to remove the reference. e.g.
var child:Sprite = new Sprite()
// one reference to the new Sprite
stage.addChild(child); // assume stage stores reference
// two references to the new Sprite
/**
* assume the following:
*
* child = null;
*
* one reference would still remain in stage
* garbage collector will not clean up the sprite
*/
stage.removeChild(child); // assume stage clears reference
// one reference left
child = null;
// no reference to the sprite, garbage collector will clean it up
Hope this clears things up a bit. Essentially you want to keep track of how many references there are to an object, if you suspect it to be leaking memory.
I know that FlashDevelop has a profiler that is quite useful for finding these bugs. Also, you need to know that when the garbage collector runs... it will free up memory and give a saw tooth pattern to your memory profiler.
Good example code for demonstrating profiling in Actionscript 3
AS3 Memory Leak Example