[解決済み] ChromeでJavaScriptのメモリリークを発見する
質問
私は、Backboneのビューを作成し、イベントにハンドラをアタッチし、ユーザー定義クラスをインスタンス化する非常に単純なテストケースを作成しました。私は、このサンプルの"Remove"ボタンをクリックすることによって、すべてがクリーンアップされ、メモリリークがないはずだと信じています。
このコードのjsfiddleはこちらです。 http://jsfiddle.net/4QhR2/
// scope everything to a function
function main() {
function MyWrapper() {
this.element = null;
}
MyWrapper.prototype.set = function(elem) {
this.element = elem;
}
MyWrapper.prototype.get = function() {
return this.element;
}
var MyView = Backbone.View.extend({
tagName : "div",
id : "view",
events : {
"click #button" : "onButton",
},
initialize : function(options) {
// done for demo purposes only, should be using templates
this.html_text = "<input type='text' id='textbox' /><button id='button'>Remove</button>";
this.listenTo(this,"all",function(){console.log("Event: "+arguments[0]);});
},
render : function() {
this.$el.html(this.html_text);
this.wrapper = new MyWrapper();
this.wrapper.set(this.$("#textbox"));
this.wrapper.get().val("placeholder");
return this;
},
onButton : function() {
// assume this gets .remove() called on subviews (if they existed)
this.trigger("cleanup");
this.remove();
}
});
var view = new MyView();
$("#content").append(view.render().el);
}
main();
しかし、Google Chromeのプロファイラを使って、実際にそうであるかどうかを確認する方法が不明である。ヒーププロファイラのスナップショットにはたくさんのものが表示されますが、何が良くて何が悪いのかを判断する方法が全く分かりません。私がこれまで見たチュートリアルは、単にスナップショットプロファイラを使えというものでしたし、プロファイラ全体の仕組みについて非常に詳細なマニフェストを与えてくれるものでもありませんでした。プロファイラをツールとして使うだけでいいのでしょうか、それとも全体がどのように設計されているかを理解しなければならないのでしょうか?
EDITです。 こんなチュートリアルも。
私が見た限りでは、より強力な資料の代表格です。しかし 3 スナップショットテクニック 私のような初心者には)実践的な知識はほとんどないように思います。チュートリアルの「DevToolsを使う」は、実例を挙げていないので、曖昧で一般的な概念の説明で、あまり役に立ちません。Gmail」の例については。
<ブロッククオートそれで、あなたは漏水を発見しました。さて、どうする?
-
プロファイルパネルの下半分で、リークしたオブジェクトの保持パスを確認する
-
割り当て先が容易に推測できない場合(イベントリスナーなど)。
-
JSコンソールを介してretainオブジェクトのコンストラクタをインストルメントし、アロケーションのスタックトレースを保存します。
-
クロージャを使用する場合 適切な既存のフラグ (たとえば goog.events.Listener.ENABLE_MONITORING) を有効にして、構築中に creationStack プロパティを設定します。
それを読んだ後では、混乱はなくなるどころか、もっと混乱していることに気づきました。そしてまた、それは私にこう言っているのです。 する のことであって いかに を行うことです。私の目から見ると、世の中の情報はどれも漠然としているか、すでにそのプロセスを理解している人にしか理解できないものばかりです。
このような、より具体的な問題点については、いくつか ジョナサン・ナギンの回答 以下のとおりです。
どのように解決するのですか?
メモリリークを発見するための良いワークフローは スリースナップショット このテクニックは、Loreena LeeとGmailチームがメモリ問題を解決するために最初に使用したものです。その手順は、一般的に
- ヒープスナップショットを取得します。
- 何かをする。
- 別のヒープスナップショットを取得します。
- 同じことを繰り返す。
- 別のヒープスナップショットを取る。
- スナップショット3のquot;Summary"ビューで、スナップショット1と2の間に割り当てられたオブジェクトをフィルタリングします。
あなたの例のために、このプロセスを示すコードを適応しました(あなたはそれを見つけることができます ここで ) Backbone Viewの作成をStartボタンのクリックイベントまで遅らせています。さて
- HTMLを実行します。 アドレス )し、スナップショットを取る。
- Startをクリックして、ビューを作成します。
- 別のスナップショットを撮る。
- 削除をクリックします。
- 別のスナップショットを撮る。
- スナップショット3のquot;Summary"ビューで、スナップショット1と2の間に割り当てられたオブジェクトをフィルタリングします。
これでメモリリークを発見する準備が整いました!
いくつかの異なる色のノードがあることに気づかれるでしょう。赤いノードは、Javascript から直接参照されていませんが、切り離された DOM ツリーの一部であるため、生きています。ツリーには、Javascript から参照されているノードがあるかもしれませんが (おそらくクロージャまたは変数として)、偶然にも DOM ツリー全体がガベージコレクションされるのを防いでいるのです。
ただし、黄色いノードはJavascriptから直接参照されています。同じように切り離されたDOMツリーで黄色のノードを探し、Javascriptからの参照を見つけます。DOM ウィンドウから要素につながるプロパティの連鎖があるはずです。
あなたのこだわりでは、赤でマークされたHTMLのDiv要素が見えると思います。その要素を展開すると、それが "cache" 関数によって参照されていることがわかります。
行を選択し、コンソールに「$0」と入力すると、実際の機能と位置が表示されます。
>$0
function cache( key, value ) {
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
if ( keys.push( key += " " ) > Expr.cacheLength ) {
// Only keep the most recent entries
delete cache[ keys.shift() ];
}
return (cache[ key ] = value);
} jquery-2.0.2.js:1166
これは、あなたの要素が参照されているところです。残念ながら、これはjQueryの内部メカニズムであり、あなたができることはあまりありません。しかし、テストのために、この関数に移動して、メソッドを変更してください。
function cache( key, value ) {
return value;
}
これで、このプロセスを繰り返すと、赤いノードが表示されなくなります :)
ドキュメンテーションです。
関連
-
Vueのクラススタイルの使い方の詳細
-
[解決済み】ローカルファイルを開くことができません - Chrome: ローカルリソースの読み込みが許可されていない
-
[解決済み] JavaScriptで "use strict "は何をするのか、その根拠は?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] JavaScriptで現在のURLを取得する?
-
[解決済み】JavaScriptの比較では、どちらの等号演算子(== vs ===)を使うべきですか?
-
[解決済み】オブジェクトからプロパティを削除する(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 実装 サイバーパンク風ボタン
おすすめ
-
要素ツリー制御によるvueTreeテーブル
-
vue3.0プロジェクトのアーキテクチャを構築するための便利なツール
-
HTML+CSS+JavaScriptで簡単な三目並べゲームを作成する。
-
vue+webrtc(Tencent cloud)ライブ機能の実践を実現するために
-
Vueでルートネスティングを実装する例
-
vueにおけるfilterの適用シーンについて解説します。
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み] 配列の結合時に未定義のプロパティ 'push' を読み込むことができない
-
[解決済み】awaitは非同期関数でのみ有効です。
-
[解決済み】 Uncaught TypeError : undefined のプロパティ 'replace' を読み取れない In Grid