Example show that don't nulled variables hold instances for a long time, and maybe forever.
So good advice - to null local variable if you use closure.
## UPDATE
Memory Leaks can be fit with System.gc(). Look here:
http://wonderfl.net/c/mb50 - Closure Memory Leak with System.gc().
So them will be removed in mark/sweep phase http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/garbage-collection.html but anyway it's performance cost phase and better to avoid using of closures.
/**
* Copyright hyzhaka ( http://wonderfl.net/user/hyzhaka )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/iWFL
*/
package {
import flash.text.TextField;
import flash.utils.setTimeout;
import flash.utils.Dictionary;
import flash.display.Sprite;
import com.actionscriptbible.Example;
/**
* Example show that don't nulled variables hold instances for a long time, and maybe forever.
*
* So good advice - to null local variable if you use closure
*
*/
public class ClosureLeaks extends Example {
private var _pool:Dictionary = new Dictionary(true);
public function ClosureLeaks() {
buildClosureTests(3, 200);
logTestInstancesRightNow();
setTimeout(logTestInstancesBeforeFree, 100);
setTimeout(logTestInstancesAfterFree, 300);
setTimeout(logClosureInstanceBeforeFree, 100);
setTimeout(logClosureInstanceAfterFree, 300);
}
/**
* Create some instance of test class, and execute closure test in each
*/
private function buildClosureTests(i:int, freeTime:int):void {
while(--i>=0) {
var instance:ClosureLeaksTest = new ClosureLeaksTest(i.toString(), freeTime).execute();
_pool[instance] = true;
}
_pool[new ClosureLeaksTest("don't execute method with clouse", freeTime)] = true;
}
/**
* Show state of closure tests before free in closure test
*/
private function logTestInstancesRightNow():void {
trace("\n## Test Instances right now");
logPool(_pool);
}
/**
* Show state of closure tests before free in closure test
*/
private function logTestInstancesBeforeFree():void {
trace("\n## Test Instances before free");
logPool(_pool);
}
/**
* Show state of closure tests after free in closure test
*/
private function logTestInstancesAfterFree():void {
trace("\n## Test Instances after free");
logPool(_pool);
}
private function logClosureInstanceBeforeFree():void {
trace("\n## Before free instance");
logPool(ClosureLeaksTest._pool);
}
private function logClosureInstanceAfterFree():void {
trace("\n## After free instance");
logPool(ClosureLeaksTest._pool);
}
private function logPool(pool:Dictionary):void {
for(var instanceAfter:* in pool) {
trace("* instance: '", instanceAfter.name, "'");
}
}
}
}
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.text.TextField;
import flash.utils.setTimeout;
import flash.utils.Dictionary;
import flash.display.Sprite;
/**
* Execute test with closure function
*
*/
class ClosureLeaksTest{
public static var _pool:Dictionary = new Dictionary(true);
private var _name:String;
private var _freeTime:int;
public function ClosureLeaksTest(name:String, freeTime:int) {
_name = name;
_freeTime = freeTime;
}
/**
* Execute clouse test
*/
public function execute():ClosureLeaksTest {
var nulledInstance:Object = {name:"nulled instance of " + _name};
var doenstNulledInstance:Object = {name:"doenst nulled instance of " + _name};
_pool[nulledInstance] = true;
_pool[doenstNulledInstance] = true;
//Here is closure!
var timer:Timer = new Timer(_freeTime, 1);
timer.addEventListener(TimerEvent.TIMER, function():void {
//hack to remove instance from closure scope
nulledInstance = null;
});
timer.start();
return this;
}
public function get name():String {
return _name;
}
}