[解決済み] JavaScriptのクロージャはどのようにガベージコレクションされるのか
質問
以下のようなログを記録しました。 Chromeのバグ これは、私のコードに多くの深刻で明白でないメモリリークを引き起こしました。
(この結果はChrome Dev Toolsの メモリプロファイラ GCを実行し、収集されたガーベッジされていないすべてのヒープスナップショットを取ります)。
以下のコードでは
someClass
インスタンスはガベージコレクションされます(良いことです)。
var someClass = function() {};
function f() {
var some = new someClass();
return function() {};
}
window.f_ = f();
しかし、この場合ガベージコレクションされない(悪い)。
var someClass = function() {};
function f() {
var some = new someClass();
function unreachable() { some; }
return function() {};
}
window.f_ = f();
そして、それに対応するスクリーンショット。
どうやらクロージャ(この場合。
function() {}
) は、そのオブジェクトが同じコンテクスト内の他のクロージャによって参照されている場合、そのクロージャ自体が到達可能かどうかに関わらず、すべてのオブジェクトを "alive" 保持します。
私の質問は、他のブラウザ(IE 9+とFirefox)におけるクロージャのガベージコレクションについてです。私は JavaScript ヒープ プロファイラなどの webkit のツールにはかなり詳しいのですが、他のブラウザのツールについてはほとんど知らないので、これをテストすることはできませんでした。
IE9+とFirefoxは、この3つのうちどのケースでガベージコレクションを行うのでしょうか?
someClass
のインスタンスですか?
解決方法は?
IE9+とFirefoxでテストしてみました。
function f() {
var some = [];
while(some.length < 1e6) {
some.push(some.length);
}
function g() { some; } //removing this fixes a massive memory leak
return function() {}; //or removing this
}
var a = [];
var interval = setInterval(function() {
var len = a.push(f());
if(len >= 500) {
clearInterval(interval);
}
}, 10);
ライブサイト こちら .
500の配列になることを期待しました。
function() {}
を、最小限のメモリで実現しました。
残念ながら、そうはいきませんでした。空の関数はそれぞれ、100万個の数値からなる(永遠に到達できないがGCされていない)配列を保持していたのです。
Chrome は最終的に停止して死に、Firefox は 4GB 近くの RAM を使用した後にすべてを終了し、IE は "メモリ不足" を表示するまで漸近的に遅くなりました。
コメントされている行のどちらかを削除すると、すべてが修正されます。
この3つのブラウザ(Chrome、Firefox、IE)はいずれも、クロージャごとではなく、コンテキストごとに環境記録を保持しているようです。Borisはこの決定の背景にある理由をパフォーマンスだと仮定しており、それはありそうですが、上記の実験に照らしてどの程度パフォーマンスと呼べるかはわかりません。
を参照するクロージャが必要な場合
some
(もちろん、ここでは使っていませんが、使ったと想像してください)。
function g() { some; }
を使っています。
var g = (function(some) { return function() { some; }; )(some);
は、クロージャを私の他の関数とは異なるコンテキストに移動させることで、メモリの問題を解決します。
これで、私の人生はもっと面倒なものになる。
追伸:興味本位で、これをJavaで試してみました(関数の中にクラスを定義する機能を使って)。GCは、私がJavascriptに当初期待していたように動作します。
関連
-
vueネットワークリクエストソリューション ネイティブネットワークリクエストとjsネットワークリクエストライブラリ
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでメールアドレスを検証するのに最適な方法は何ですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
-
[解決済み】オブジェクトからプロパティを削除する(JavaScript)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vueがechartsのtooltipにクリックイベントを追加するケーススタディ
-
Vueはランニングライト形式のテキストを水平方向にスクロールする機能を実装している
-
Javascript Bootstrapのグリッドシステム、ナビゲーションバー、ローテーションの説明
-
Vueのクラススタイルの使い方の詳細
-
Vueの「データを聴く」原則を解説
-
[解決済み】最大呼び出しスタックサイズ超過エラー
-
[解決済み】awaitは非同期関数でのみ有効です。
-
[解決済み】 `string.split is not a function` というエラーの原因は何ですか?
-
[解決済み】React Uncaught Error: 対象コンテナが DOM 要素でない [重複]。
-
JavaScriptのStringに関する共通メソッド