[ActionScript 3.0] クロージャが原因のメモリリーク
クロージャを利用した場合、それを内包する関数(メソッド)におけるローカル変数の状態のまとまりを、そのクロージャが実際に呼び出されたときのために、スクリプトエンジン(Flash PlayerやAIR)が保持しつづける。
そのため、ローカル変数のオブジェクトは関数終了後も破棄されず、クロージャを保持しているオブジェクトが破棄されないかぎり、ずっとメモリを使用したままになる。
public class TestClosureMem extends Sprite { |
private var sampleTimer:Timer = new Timer( 50 , 20 ); |
private var checkTimer:Timer = new Timer( 200 ); |
private var fnVec:Vector.< function > = new Vector.</ function >< function >; |
public function TestClosureMem() { |
sampleTimer.addEventListener(TimerEvent.TIMER, doSample); |
sampleTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onComplete); |
checkTimer.addEventListener(TimerEvent.TIMER, checkMemory); |
private function checkMemory(e:TimerEvent): void { |
trace (System.totalMemory); |
private function doSample(e:TimerEvent): void { |
var bmpData:BitmapData = new BitmapData( 1000 , 1000 ); |
private function onComplete(e:TimerEvent): void { |
trace ( "--- closure cleared ---" ) |
fnVec = new Vector.</ function >< function >; |
この例の場合、クロージャ(無名関数)をfnVecというVectorインスタンスが保持しているから、それが破棄されないかぎりメモリは増えつづけていく。
stageからの参照のつながり(スコープチェーン)は、以下のようになっている。
stage - TestClosureMem - fnVec - 各クロージャ
よって、TestClosureMemインスタンスかfnVecがガベージコレクション(GC)の対象にならないかぎり、bmpDataは破棄されずにどんどんメモリを占有していく。
GCの仕組みがある言語でも、メモリの問題からは逃れられない。そこにクロージャがからんでくるとさらに厄介なことになるので、特段の理由がないならばあまりうかつにクロージャを使わないほうがいいのかもしれない。
ディスカッション
ピンバック & トラックバック一覧
[…] # ActionScript 3.0についてはこちら。 ツイート カテゴリー: JavaScript タグ: 文法, 重要 この投稿のパーマリンク ← [Webアプリ] Flash製ノベルゲーム『TRUTH』 […]