Total hits since 4th Jan 2010

Friday, January 29, 2010

Optimization techniques and GC

I’m personally a big fan of coding standards and writing optimized code. I appreciate others and very happy to do it. We should pay more attention while writing code rather than spending a ton of time on GC for finding reason of performance. Continuous practices and experience make you write better and better optimized code. We should follow strictly a coding standard within a team/company while writing code. We should review others code and try to learn good things from there and implement whenever it requires.

A few practices listed below and you are welcome to add more:
Avoid the new operator when creating Array. Try to use var a=[];

Fastest way to copy an array: var copy : Array = sourceArray.concat();

Setting values in Array is slow and getting from it is 2 times faster.

Use ‘static’ for properties methods that do not require an object instance.

Use ‘const’ for properties that will never change throughout the lifecycle of the application.

Use ‘final’ when no subclasses need to be created.

Length of method/variable names doesn't matter so give it suitable name for readability.

No difference in memory usage between an if statement and a switch statement.

Use integers for iterations

Multiply vs. Divide: instead of 5000/1000 use: 5000*0.001

Avoid calculations and method calls in loops: use
var len : int = myArray.length;

Understanding Garbage Collection is also important steps for writing optimized code that ensures project runs with minimal impact on the user's computer. Thanks to Grant Skinner for his contribution on this topic.

What is Garbage Collection (GC)?
Garbage collection is a process by which the memory is freed up when any object no longer used by the application. It happens automatically. Garbage collector runs at some indeterminate point so it is not in the control of developers. AS3 garbage collector uses two methods for locating objects with no active references: reference counting and mark sweeping.

Reference counting:
Reference counting is one of the simplest methods for keeping track of active objects, and has been used in Flash since AS1. When you create a reference to an object, its reference count is incremented. When you delete a reference, its reference count is decremented. If the reference count of an object reaches zero, it is marked for deletion by the garbage collector.
Example
var a:Object = {foo:"bar"}// the object now has a reference count of 1 (a)var

b:Object = a;// now it has a reference count of 2 (a & b)

delete(a);// back to 1 (b)

delete(b);// the reference countdown is now 0 the object can now be deallocated by the garbage collector.

Reference counting is simple, it doesn't carry a huge CPU overhead, and it works well in most situations. Unfortunately, the reference counting method for garbage collection is not optimal when it comes to circular referencing. Circular referencing is the situation when objects cross-reference each other (directly, or indirectly via other objects). Even if the application is no longer actively using the objects, their reference counts remain above zero, so the garbage collector never removes them. The code below illustrates how this works:

var a:Object = {}
//create a second object, and reference the first object.

var b:Object = {foo:a};
// make the first object reference the second as well.

a.foo = b;
// delete both active application references:

delete(a);
delete(b);

In the code shown above, both of the active application references have been deleted. I no longer have any way of accessing the two objects from my application, but the reference counts of both objects are 1 because they reference each other.

Mark sweeping:
Mark sweeping introduced in Flash player 8. The second strategy employed by the AS3 garbage collector to find inactive objects is a method called mark and sweep. Flash Player starts at the root object of your application (which is conveniently called the "root" in AS3) and walks through every reference in it, marking each object it finds. Flash Player iterates through each of the marked objects. It continues this behavior recursively until it has traversed the entire object tree of your application, marking everything it can reach through an active reference. At the end of this process, Flash Player can safely assume that any objects in memory that are not marked no longer have any active references to them and can be safely deallocated.
Mark and sweep is very accurate. However, because Flash Player has to traverse your entire object structure, the process is costly in terms of CPU usage. Flash Player 9 reduces this cost by carrying out iterative mark and sweep—the process occurs over a number of frames, instead of all at once—and by running this process only occasionally.

New API:
AS3 has added many new API and changed its earlier framework so require additional responsibility than before. The biggest change in AS3 that affects resource management is the new display list model. In Flash Player 8 and earlier, when a display object was removed from the screen (using removeMovie or unloadMovie), the display object and all of its children were immediately removed from memory and code execution stopped. Flash Player 9 introduces a much more flexible display list model. The display objects (Sprites, Movie clips, etc.) are now treated the same as every other object by the garbage collector. Flash developers are now to manage resource like Java.
Display objects continue to exist in memory when you remove the object from the Stage because they no longer live and die on the display list. If you have not cleaned up all other references to the clip, including the object's listeners, it may never be removed. If you have done a good job of cleaning up all references, the clip will be removed from memory the next time the garbage collector runs a sweep, which will occur at some indeterminate point in the future. It is not in the control of developer hands. There is currently no way to force Flash Player to kill a display object and stop it from executing. It is up to the Flash developer to do this manually when the object is removed from the display.
It is very important to note that not only will the display object continue to use memory, it will also continue to execute any "idle" code, such as timers, enterFrames, and listeners that are outside its scope.
In AS3, even after you remove the Display object from the display list and null all references to it, the application continues to run that code in every frame until it is removed by garbage collection. You must remember to explicitly remove the enterFrame listener when it is removed.
Similar to other display objects, there is no way to explicitly remove a loaded SWF and its contents from memory, or to stop it from executing. Calling Loader.unload simply nulls the loader's reference to the SWF; it will continue to exist and keep executing until it has been picked up by the next garbage collection sweep. Take care of the things while loading external swf that has been developed by another team and they added listeners and external assets in this file. There is no way to remove its content and it will consume CPU resources until quits the application.
Even if the loaded content does not have any external references, it will continue to execute indefinitely until the next garbage collection sweep.
It is always a good idea to think through potential vulnerabilities in your application during the development process.

Profiling:
The System class contains methods and properties that allow you to interact with the user’s operating system and retrieve the current memory usage for Flash Player or AIR. By checking the System.totalMemory property, you can determine the amount of memory (in bytes) that Flash Player or AIR is currently using. This property allows you to monitor memory usage and optimize your applications based on how the memory level changes. It can be used as a runtime profiling tool. It's always better to throw an error and abort your application, rather than bog down the user's system. You can use this basic code for runtime profiling:

import flash.system.System;
import flash.net.navigateToURL;
import flash.net.URLRequest;

// check our memory every 5 second:
var checkMemoryIntervalID:uint = setInterval(checkMemoryUsage,5000);
var showWarning:Boolean = true;
var warningMemory:uint = 500000000// show warning
var abortMemory:uint =600000000;// Abort when it has exceeded
function checkMemoryUsage()
{
if (System.totalMemory > warningMemory && showWarning) {
// show an error to the user warning them that we're running out of memory and might quit
// try to free up memory if possible
showWarning = false; // so we don't show an error every second
}
else if (System.totalMemory > abortMemory) {
// save current user data if required.
abort();
}
}
function abort() {
// send the user to a page explaining what happpened:
navigateToURL(new URLRequest("help.html"));
}
It is important to note that totalMemory is a shared value within a single process. A single process may be just one browser window, or all open browser windows, depending on the browser, the operating system, and how the windows were opened.

Conclusion: There is no longer any way to explicitly remove a display object from memory and stop its code from executing—which means all Flash developers have a responsibility to clean up properly after objects are no longer used in an application.

Regards,
Faiz

1 comment:

  1. For forceful GC, use useWeakReference = true
    wherever required.
    e.g. - addEventListener() contains the last parameter as useWeakRefernce, which is by default false.

    ReplyDelete