2013-04-27 11 views
13

JavaScriptのメモリリークの原因となるコードの種類を理解しておき、以下のスクリプトを作成しました。しかし、OS X上のSafari 6.0.4でスクリプトを実行すると、アクティビティモニタに表示されるメモリ消費量はそれほど増加しません。JavaScriptでメモリリークを作成するにはどうすればよいですか?

スクリプトに問題がありますか、これは最新のブラウザの問題ではありませんか?

<html> 
<body> 
</body> 
<script> 
var i, el; 

function attachAlert(element) { 
    element.onclick = function() { alert(element.innerHTML); }; 
} 

for (i = 0; i < 1000000; i++) { 
    el = document.createElement('div'); 
    el.innerHTML = i; 
    attachAlert(el); 
} 
</script> 
</html> 

スクリプトは、GoogleのJavaScriptのスタイルガイドの閉鎖区間に基づいています。 http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Closures

EDIT:漏れるために上記のコードを引き起こしたバグが明らかに修正されました:http://jibbering.com/faq/notes/closures/#clMem

しかし、私の誰かが現代的なブラウザでメモリをリークするJavaScriptコードの現実的な例を提供できるだろうか?

インターネットでは、複雑なシングルページアプリケーションでメモリリークが問題になることがあるとの記事がたくさんありますが、ブラウザで実行できる例が見つからない場合があります。

答えて

5

あなたが作成した要素をどこにでも保持しておらず、どこからでも参照できます。そのため、メモリ使用量が増えていないのです。 DOMに要素を添付したり、オブジェクトに格納したり、onclickを別の要素として設定したりしてください。それでは、メモリ使用量が急増するのを見るでしょう。ガベージコレクタは、参照できなくなったものをすべて取り除きます。基本的には

あなたのコードのウォークスルー:

  • 要素(エル)
  • が 要素
  • は、その要素のonclickのように機能を設定することを参照する新しい関数を作成を作成
  • 要素を新しい要素で上書きする

すべてが要素が存在します。要素にアクセスする方法がないと、onclickにはもうアクセスできません。したがって、onclickにアクセスすることはできないので、作成された関数は破壊され、関数は要素への唯一の参照を持ちます。要素も同様にクリーンアップされます。

もっと技術的な例があるかもしれませんが、それがjavascriptガベージコレクタの理解の基礎となります。

編集:、

<html> 
<body> 
</body> 
<script> 
var i, el; 

var createdElements = {}; 
var events = []; 

function attachAlert(element) { 
    element.onclick = function() { alert(element.innerHTML); }; 
} 

function reallyBadAttachAlert(element) { 
    return function() { alert(element.innerHTML); }; 
} 

for (i = 0; i < 1000000; i++) { 
    el = document.createElement('div'); 
    el.innerHTML = i; 

    /** posibility one: you're storing the element somewhere **/ 
    attachAlert(el); 
    createdElements['div' + i] = el; 

    /** posibility two: you're storing the callbacks somewhere **/ 
    event = reallyBadAttachAlert(el); 
    events.push(event); 
    el.onclick = event; 

} 
</script> 
</html> 

ので、#1のためのあなたは、単にどこかにその要素への参照を格納している。ここでは、スクリプトの漏れるのバージョンのための多くの可能性の一つです。要素を参照しているため、要素とそのコールバックは決して消えません(少なくともオブジェクトから要素を削除するまで)。可能性2のために、イベントをどこかに格納することができます。要素が見つからなくても、イベントにアクセスできる(つまりevents[10]();を実行することにより)ことができるため、イベントによって参照されているため、配列から削除されるまで、要素はイベントと同様にメモリ内に残ります。

+0

返信いただきありがとうございます。イラストレーションのために私のスクリプトの修正版を投稿できるでしょうか? – user2327642

+0

完了。うまくいけば助けてくれます。 – Stephen

+0

ありがとうございますが、これは関連する例ではないと思います。作成されたすべての要素への参照を格納する場合、それらがガベージコレクションされるとは思われません。私のコードのポイントは、クロージャが循環参照を作成するものです。サーキュラーリファレンスはガベージコレクターにとっては問題ありませんが、私が今学んだように、サーキュラーリファレンスに含まれるオブジェクトの1つがDOMエレメントであったときにガベージコレクションが動作しないバグがありました。 – user2327642

関連する問題