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.
Related
Summary:
I'm trying to find out if a single method can be executed twice in overlap when executing on a single thread. Or if two different methods can be executed in overlap, where when they share access to a particular variable, some unwanted behaviour can occur.
Ex of a single method:
var ball:Date;
method1 ():Date {
ball = new Date();
<some code here>
return ball;
}
Questions:
1) If method1 gets fired every 20ms using the event system, and the whole method takes more than 20ms to execute, will the method be executed again in overlap?
2) Are there any other scenarios in a single thread environment where a method(s) can be executed in overlap, or is the AVM2 limited to executing 1 method at a time?
Studies: I've read through https://www.adobe.com/content/dam/Adobe/en/devnet/actionscript/articles/avm2overview.pdf which explains that the AVM2 has a stack for running code, and the description for methods makes it seem that if there isn't a second stack, the stack system can only accomodate 1 method execution at a time. I'd just like to double check with the StackeOverflow experts to see for sure.
I'm dealing with some time sensitive data, and have to make sure a method isn't changing a variable that is being accessed by another method at the same time.
ActionScript is single-threaded; although, can support concurrency through ActionScript workers, which are multiple SWF applications that run in parallel.
There are asynchronous patterns, if you want a nested function, or anonymous function to execute within the scope chain of a function.
What I think you're referring to is how AVM2 executes event-driven code, to which you should research AVM2 marshalled slice. Player events are executed at the beginning of the slice.
Heavy code execution will slow frame rate.
It's linear - blocking synchronously. Each frame does not invoke code in parallel.
AVM2 executes 20 millisecond marshalled slices, which depending on frame rate executes user actions, invalidations, and rendering.
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.
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.
Is flash smart enough to "hide" PIXELS that aren't on the stage, in order to decrease memory usage? Or I must do it manually, if it decreases the memory usage at all?
Flash does not render objects that aren't on the stage (as per http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e3e.html).
However I think you may be mixing up two different issues.
One issue is CPU/GPU performance - for this there is no need to worry about off-stage objects as Flash does not waste time rendering display objects that are outside the stage bounds.
The other issue is memory usage. Every object that you create takes up some memory whether or not it is visible on the screen. Flash has a garbage collector that will periodically dispose of unused objects, however "unused objects" means an object that isn't referenced by any other object so if you are having memory issues you will have to manually clean up objects by removing event listeners, nulling references etc.
There's nothing like that available to decrease memory usage. If it's visible on your monitor, it needs to be rendered by Flash and have a place in memory storing the pixel colour.
Although Flash is very fast these days, especially with hardware acceleration. So you shouldn't worry too much about performance, there's a lot of bang for your virtual buck with AS3. I'd bet all of my virtual dollars on it.
Flash will store all bitmaps, movieclips in fact all objects in memory as expected. If you have a large bitmap which is larger than the stage, it still occupies memory regardless of you only showing a portion of it.
If you have multiple bitmaps or movieclips that may move off the stage and no part of them are visible, then the only way to recover memory is to make sure the object is dereferenced and set to null.
myMovieClip = null;
Prior to setting to null you would also have to make sure that nothing else is referencing the object, for example it can't be stored in an array or have any event listeners attached to it so therefore:
myMovieClip.removeEventListener(Event.WHATEVER, eventHandler);
For bitmapdata objects you would need to call dispose first before setting to null:
myBitmapdata.dispose();
myBitmapdata = null;
This then allows the GC to recover memory when it chooses, unless you are using AIR which means you may request a gc call yourself:
System.gc();
If you are developing in Flash Builder, the best practice is to regularly profile your application and hit the button to force a gc call. You can then see which objects are persisting in memory and locate the references which are causing the memory leaks.
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.