Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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".

like image 811
Martin Cowie Avatar asked Aug 26 '14 18:08

Martin Cowie


People also ask

How do I reduce the pause time on my GC?

If your application's object creation rate is very high, then to keep up with it, the garbage collection rate will also be very high. A high garbage collection rate will increase the GC pause time as well. Thus, optimizing the application to create fewer objects is THE EFFECTIVE strategy to reduce long GC pauses.

What does GC pause mean?

Garbage collection (GC) is the process by which Java removes data that is no longer needed from memory. A garbage collection pause, also known as a stop-the-world event, happens when a region of memory is full and the JVM requires space to continue. During a pause all operations are suspended.


1 Answers

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

like image 104
dreamlab Avatar answered Oct 12 '22 14:10

dreamlab