forked from: Unexpected Memory Leak (無名関数の濫用はメモリリークの温床!)

by bkzen forked from Unexpected Memory Leak (無名関数の濫用はメモリリークの温床!) (diff: 100)
----------------------------------------------------------------------------
* An unexpected memory leak can be caused by the abuse of function closure!
* ----------------------------------------------------------------------------
* 最近知った知識を他人にやたら得意げにひけらかしたがるは人の常。
* 理解していたようであまり意識してなかった・・・という方も多いのではないかと勝手に推測。
* 
* [see also]
* アクティベーションオブジェクトによるメモリリーク
* http://www.imajuk.com/blog/archives/2008/04/post_3.html
* ----------------------------------------------------------------------------
* [適当な要約]
* ・無名関数は、望む望まざる・必要不必要に関わらず、定義されたスコープ内の"全ての"ローカル変数を保存する。
* ・無名関数が破棄されるまで、全く不用なローカル変数であっても破棄されず、メモリを無駄に占有し続ける。
* 
* [教訓]
* ・別にメソッドを定義するのが面倒だという理由だけで、無名関数を書くのはなるべく控えよう。
* ・クロージャを使いたい時は、クロージャを生成して返すメソッドを別に用意しよう。
* ----------------------------------------------------------------------------
* [補足]
* 実行する環境等によって、使用中のメモリが表示に正しく反映されない場合があります。
* ( http://www.justsuppose.com/some-systemgc-and-systemtotalmemory-tips/ )
* 開始時のメモリ使用量が30MB超~になるような環境でお試しください。
♥0 | Line 102 | Modified 2010-04-06 19:10:43 | MIT License
play

ActionScript3 source code

/**
 * Copyright bkzen ( http://wonderfl.net/user/bkzen )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/zjmp
 */

// forked from o8que's Unexpected Memory Leak (無名関数の濫用はメモリリークの温床!)
/* ----------------------------------------------------------------------------
 * An unexpected memory leak can be caused by the abuse of function closure!
 * ----------------------------------------------------------------------------
 * 最近知った知識を他人にやたら得意げにひけらかしたがるは人の常。
 * 理解していたようであまり意識してなかった・・・という方も多いのではないかと勝手に推測。
 * 
 * [see also]
 * アクティベーションオブジェクトによるメモリリーク
 * http://www.imajuk.com/blog/archives/2008/04/post_3.html
 * ----------------------------------------------------------------------------
 * [適当な要約]
 * ・無名関数は、望む望まざる・必要不必要に関わらず、定義されたスコープ内の"全ての"ローカル変数を保存する。
 * ・無名関数が破棄されるまで、全く不用なローカル変数であっても破棄されず、メモリを無駄に占有し続ける。
 * 
 * [教訓]
 * ・別にメソッドを定義するのが面倒だという理由だけで、無名関数を書くのはなるべく控えよう。
 * ・クロージャを使いたい時は、クロージャを生成して返すメソッドを別に用意しよう。
 * ----------------------------------------------------------------------------
 * [補足]
 * 実行する環境等によって、使用中のメモリが表示に正しく反映されない場合があります。
 * ( http://www.justsuppose.com/some-systemgc-and-systemtotalmemory-tips/ )
 * 開始時のメモリ使用量が30MB超~になるような環境でお試しください。
 */
package 
{
	import flash.display.BitmapData;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.MouseEvent;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.utils.getTimer;
	import net.hires.debug.Stats;
	
	public class Main extends Sprite 
	{
		private var stats:Stats;
		private var txt: TextField;
		
		public function Main(): void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e: Event = null): void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			//
			stage.addEventListener(MouseEvent.CLICK, onClick);
			addChild(txt = new TextField());
			addChild(stats = new Stats);
			txt.x = stats.width;
			txt.autoSize = TextFieldAutoSize.LEFT;
			tr("test1 ステージをクリックすると、大きなBitmapDataが作られます。");
		}
		
		private function onClick(e:MouseEvent):void 
		{
			stage.removeEventListener(MouseEvent.CLICK, onClick);
			test1();
		}
		
		private function test1():void
		{
			stage.addEventListener(MouseEvent.CLICK, function(e: MouseEvent): void {
				e.currentTarget.removeEventListener(MouseEvent.CLICK, arguments.callee);
				tr("removeEventListener");
				tr("次の実験に移ります");
				gc();
				test2();
			});
			var i: int, n: int = 2, a: Array = [];
			for (i = 0; i < n; i++) 
			{
				a[i] = new BitmapData(2880, 2880, true, 0xFFFFFFFF);
			}
			tr("次に ステージをクリックすると removeEventListener されます");
		}
		
		private function test2():void
		{
			stage.addEventListener(MouseEvent.CLICK, function(e: MouseEvent): void {
				e.currentTarget.removeEventListener(MouseEvent.CLICK, arguments.callee);
				var i: int, n: int = 2, a: Array = [];
				for (i = 0; i < n; i++) 
				{
					a[i] = new BitmapData(2880, 2880, true, 0xFFFFFFFF);
				}
				var ed: EventDispatcher = EventDispatcher(e.currentTarget);
				ed.addEventListener(MouseEvent.CLICK, function(ev: MouseEvent): void {
					ev.currentTarget.removeEventListener(MouseEvent.CLICK, arguments.callee);
					tr("removeEventListener");
					tr("次の実験に移ります。");
					gc();
					tr("test3 ステージをクリックすると大きなBitmapDataが作られます。");
					ed.addEventListener(MouseEvent.CLICK, function(eve: MouseEvent): void {
						eve.currentTarget.removeEventListener(MouseEvent.CLICK, arguments.callee);
						var i: int, n: int = 2, a: Array = [];
						for (i = 0; i < n; i++) 
						{
							a[i] = new BitmapData(2880, 2880, true, 0xFFFFFFFF);
						}
						tr("次に ステージをクリックすると removeEventListener されます");
						eve.currentTarget.addEventListener(MouseEvent.CLICK, function(event: MouseEvent): void {
							event.currentTarget.removeEventListener(MouseEvent.CLICK, arguments.callee);
							tr("removeEventListener");
							tr("終了");
							gc();
						});
					});
				});
				tr("次に ステージをクリックすると removeEventListener されます");
			});
			tr("test2 ステージをクリックすると大きなBitmapDataが作られます。");
			
		}
		
		private function tr(...args: Array): void 
		{
			txt.appendText("" + args + "\n");
			if (txt.height > stage.stageHeight)
			{
				txt.y = stage.stageHeight - txt.height;
			}
		}
		
		private function gc(): void
		{
			new BitmapData(2880, 2880, true, 0xFFFFFFFF).dispose();
		}
	}
}