AS3 - when does the garbage collector run? - actionscript-3

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.

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.

Flex 3 Memory leak issue

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.

Manage resources to minimize garbage collection activity and improve performance

I am working on a graphic design, vector drawing application that needs to render the data in every frame when there is a change. The issue is, that if the user is moving nodes, there will be changes during every single frame. This is not an issue with a tiny amount of data and is a major slowdown when there is anything more than a minor amount of data.
The reason is that in order to render I preform calculations and store data inside arrays. Then when the function responsible for the computation is done, the GC simply discards the data and next time the function is called, we create new arrays and new data.
In C++ I would probably allocate space in the memory and write to that space(over and over). I would probably improve performance that way. In languages that us GC I cannot allocate space that way. I have to do an ugly hack where I define an array as a class member and then write to that array from the function over and over although that array is only used in that one function and is not used by other methods of the class.
My questions is, what is the best way to reuse memory space in a language that uses GC?
Object pooling would be the major one, see here:
Gotoandplay Tutorial
Also
10 Top Tips around GC
I would also suggest you read through Grant's explanation of the garbage collection system in the Flash Player, it's quite unique, and understanding how Flash handles data is quite important to data intensive scripts.
This presentation

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

Why do garbage collectors freeze execution?

I was thinking about garbage collection on the way home, and I began wondering, why does the garbage collector totally freeze execution of a program? Personally I would have designed it to block any threads which try to allocate a new object, but threads which were running would be left alone.
I can't imagine any situation where this would be a problem compared to how a garbage collector currently works.
I was thinking about garbage collection on the way home, and I began wondering, why does the garbage collector totally freeze execution of a program?
There is a trade-off between latency and throughput in GC design. You can either process heap-allocated blocks individually ("incremental") or you can batch them up and process them all at the same time ("stop the world"). Fully incremental collection never totally freezes a program and it has very low latency but it also has very poor throughput. Stop the world garbage collectors have the worst possible latency (freezing the program for seconds or even minutes at a time) but near-optimal throughput.
All of the major production GCs today provide a middle ground, typically with generational collection with the per-thread nursery generations collected in batches and incremental or concurrent collection of the shared old generation. Thus, only nursery collections incur pauses and nursery size is bounded so pause times are kept low, e.g. 10-100ms in .NET with the workstation GC.
For a simple GC algorithm that never pauses, see Baker's Treadmill. For more information on garbage collection I highly recommend the Memory Management Reference and the Garbage Collection Handbook.
There is a lot of misinformation in the other answers here. Jon Skeet wrote some source code and started discussing it from the point of view of garbage collection. You need to be very careful doing this because there is little correspondence between source code and what the GC sees. The compiler does instruction block rearrangements, register allocation, promotion and so on, all of which affect what is visible to the GC at run time. In particular, scope in source code is not carried through to compiled code and is typically replaced with the related concept of liveness. Jon also wrote that you must pause in order to get the global roots. That is not strictly true although it is the most efficient way to get the global roots and the resulting pause is almost always tiny (sub-millisecond) because you're just copying less than a kB of stack from each thread.
Powerlord wrote that moving collectors must block reads and, therefore, all threads that read. This is also not true. The simplest counter example is immutable data: referential transparency means you can read from any copy safely.
Kico wrote that pauses are required to determine reachability. This is also not true. See Dijkstra's research about "on-the-fly" collectors and any recent real-time GC such as Stacatto.
Jerry Coffin wrote the best answer but moving isn't the reason GCs pause. There are GCs that don't move but do pause (e.g. HLVM's) and those that do move but don't pause (e.g. Stacatto).
Modern garbage collectors (in .NET and Java, anyway) don't actually "stop the world" - they do all kinds of clever things to collect concurrently.
However, you might want to consider a situation like this:
object x = null;
object y = new object();
...
x = y;
y = null;
Now, suppose the GC looks at x, then the lines below the ... run, and then the GC looks at y - it won't have seen any live objects... but the object should still be live.
Basically there needs to be a certain amount of pausing in order to get a consistent set of references. Then there's compaction, reference reassignment etc. However, it isn't nearly as bad as it used to be in terms of requiring everything to be stopped for the whole of the GC cycle. It does, however, get painful to think about :)
In addition to what Kico Lobo said, Garbage Collectors can also move things around in memory.
Therefore, they don't just have to block threads that write to memory, but also threads that read from memory.
Which is every thread.
Most GCs stop execution because objects can move in memory during a collection cycle (at least with most reasonably recent designs). That means either reading or writing almost any object at the wrong time can cause a problem.
There are collectors that have been designed around the idea of just blocking reads (or writes) to the specific parts of memory being modified at a given time, so as long as execution only uses objects that aren't (currently) being moved around, it can proceed unhindered. The problem is that most typical hardware doesn't provide efficient support for this, so even though they work in principle, they're fairly inefficient in practice. There has been at least one attempt at adapting that type of algorithm to use the write protection available in a typical paging unit, but I'm not aware of its having been used for much other than research and experimentation.
The primary alternative is to make the collector incremental -- i.e. have it do only a small amount of work at a time, so even though other execution gets stopped, it only has to stop for a little while at any given time.
With multi-core machines becoming so common, however, I'd expect to see more work put into garbage collection algorithms that can run in parallel with other execution. Up until recently, the primary emphasis was on minimizing the total time/effort spent on garbage collection. The growing number of cores available is likely to (often) mean that doing more total work in garbage collection may be easily justified, if doing so allows the mainstream of the code to run with fewer hindrances.
Edit: You might want to read Paul Wilson's Survey of Uniprocessor Garbage Collection Techniques. This isn't definitive (especially any more, given its age), but it's at least a reasonable starting point.
Because that's the only way it can assure that the refereces it is going to clean are not been used by anyone else.
If it didn´t freezed the execution, it could not assure that.