Duke Software: ActionScript 3.0 でのSoundのメモリリーク解消方法の投稿にブックマークをして下さっている方がいるのに、自分で何もテストしないのはお恥ずかしいので、Flashのメモリ管理、特にガーベッジコレクションについてその挙動を調べてみました!
結論から書きますと、Arrayを使うのが最も安全なようです。(あくまで私がテストした環境においてです。保証はできません。)System.gc();を明示的に呼び出せば、下記でテストしたすべての場合でメモリが開放されますが、System.gc();はデバッグ版のFlash Playerでしか呼びさせなかったはずなので、止めておいた方が無難だと思います。
テスト環境
Flex :Flex 3.5 (build 12683)
Flash Player:WIN 10,0,42,34 (Capabilities.versionから取得)
方法:
1) クラスにフィールド(1. Array, 2. Object, 3. 自作のdynamicクラス)を定義
2) 画面をクリックするごとに、Vector.オブジェクトを生成して1)で定義したフィールドに代入
3) クリック直後とクリックイベント検知1秒後のメモリ使用量をSystem.totalMemoryで取得
1. Array - すぐに開放される
Initial : 5201920
After : 9445376
After : 9445376
1 sec after : 5443584
After : 9445376
1 sec after : 5443584
After : 9445376
2. Object - 開放されない
Initial : 5201920
After : 9445376
1 sec after : 9445376
After : 13447168
1 sec after : 13447168
After : 17448960
1 sec after : 17448960
3. Original Defined Dynamic Class - 開放されない
Initial : 5210112
After : 9449472
1 sec after : 9449472
After : 13451264
After : 17453056
1 sec after : 17453056
1 sec after : 17453056
上記のテストで使ったGarbageCollectorTestBaseクラスのソースコードを以下に示します。
結論から書きますと、Arrayを使うのが最も安全なようです。(あくまで私がテストした環境においてです。保証はできません。)System.gc();を明示的に呼び出せば、下記でテストしたすべての場合でメモリが開放されますが、System.gc();はデバッグ版のFlash Playerでしか呼びさせなかったはずなので、止めておいた方が無難だと思います。
テスト環境
Flex :Flex 3.5 (build 12683)
Flash Player:WIN 10,0,42,34 (Capabilities.versionから取得)
方法:
1) クラスにフィールド(1. Array, 2. Object, 3. 自作のdynamicクラス)を定義
2) 画面をクリックするごとに、Vector.
3) クリック直後とクリックイベント検知1秒後のメモリ使用量をSystem.totalMemoryで取得
1. Array - すぐに開放される
結果
package test
{
/**
* The most safe way...
*
* @author Duke
*/
public class GarbageCollectorArrayPropertyTest extends GarbageCollectorTestBase
{
private var a:Array = new Array(1);
public function GarbageCollectorArrayPropertyTest()
{
}
protected override function createObject():void
{
// Yeah garbage collection is triggerd and works properly :)
a[0] = new Vector.(LEN);
delete a[0];
a[0] = null;
}
}
}
Initial : 5201920
After : 9445376
After : 9445376
1 sec after : 5443584
After : 9445376
1 sec after : 5443584
After : 9445376
2. Object - 開放されない
結果
package test
{
/**
*
* @author Duke
*/
public class GarbageCollectorObjectPropertyTest extends GarbageCollectorTestBase
{
private var o:Object = new Object();
public function GarbageCollectorObjectPropertyTest()
{
}
protected override function createObject():void
{
// Garbage collector is not triggered as long as you don't call System.gc() explicitly
o.test = new Vector.(LEN);
o.test.length = 0;
delete o.test;
// System.gc();
// Even if adding the code like below, it does not help...
// o = null;
// o = new Object();
}
}
}
Initial : 5201920
After : 9445376
1 sec after : 9445376
After : 13447168
1 sec after : 13447168
After : 17448960
1 sec after : 17448960
3. Original Defined Dynamic Class - 開放されない
結果
package test
{
/**
*
* @author Duke
*/
public class GarbageCollectorOriginalDynamicPropertyTest extends GarbageCollectorTestBase
{
private var d:OriginalDynamicObject = new OriginalDynamicObject();
public function GarbageCollectorOriginalDynamicPropertyTest()
{
}
protected override function createObject():void
{
// Garbage collector does not help as long as you don't call System.gc() explicitly
d.property = new Vector.(LEN);
delete d.property;
d.property = null;
// System.gc();
}
}
}
package test
{
/**
*
* @author Duke
*/
public dynamic class OriginalDynamicObject
{
public function OriginalDynamicObject()
{
}
}
}
Initial : 5210112
After : 9449472
1 sec after : 9449472
After : 13451264
After : 17453056
1 sec after : 17453056
1 sec after : 17453056
上記のテストで使ったGarbageCollectorTestBaseクラスのソースコードを以下に示します。
package test
{
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.system.System;
import flash.utils.Timer;
/**
*
* @author Duke
*/
public class GarbageCollectorTestBase extends Sprite
{
public static const DELAY:int = 1000;
public static const LEN:int = 1000000;
public function GarbageCollectorTestBase()
{
trace("Initial : " + System.totalMemory);
this.stage.addEventListener(MouseEvent.CLICK, mouseClicked, false, 0, true);
}
private function mouseClicked(e:MouseEvent):void
{
createObject();
trace("After : " + System.totalMemory);
var t:Timer = new Timer(DELAY, 1);
t.addEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
t.start();
}
protected function createObject():void {}
private function onTimer(ext:TimerEvent):void {
((ext.currentTarget) as Timer).removeEventListener(TimerEvent.TIMER_COMPLETE, onTimer);
trace((DELAY/1000.0) + " sec after : " + System.totalMemory);
}
}
}
コメント