メモリ リークによって引き起こされる潜在的な問題: 速度の低下、遅延、待ち時間の増加。
)。 いわゆる「不要な参照」とは、開発者にとって不要になったメモリがいくつかありますが、何らかの理由でこれらのメモリがまだマークされており、アクティブなルート ツリーに残っていることを指します。不要な参照とは、これらの記憶への参照を指します。 JavaScript のコンテキストでは、不要な参照は使用されなくなった変数であり、解放された可能性のあるメモリを指します。
シナリオ 1: JavaScript で、宣言されていない変数を参照すると、グローバル環境に新しい変数が作成されます。
function foo(arg) { bar = "this is a hidden global variable"; }
上記のコード文字列は実際には次のとおりです:
function foo(arg) { window.bar = "this is an explicit global variable"; }
bar 変数を foo 関数のスコープ内でのみ使用したいが、上記の状況が誤って使用されてしまう場合スコープ内でグローバルに bar を作成すると、メモリ リークが発生します。
シナリオ 2:
function foo() { this.variable = "potential accidental global"; }foo();
同様に、変数 bar を foo 関数のスコープ内でのみ使用したいが、foo 関数内の this が次を指していることがわからない場合グローバル オブジェクトの場合、メモリが優先されます。
推奨事項:
for (var i = 0; i < 100000; i++) { var buggyObject = { callAgain: function () { var ref = this; var val = setTimeout(function () { ref.callAgain(); }, 10); } } buggyObject.callAgain(); buggyObject = null;}
多处引用(Multiple references):当多个对象均引用同一对象时,但凡其中一个引用没有清除,都将导致被引用对象无法GC。
场景一:
var elements = { button: document.getElementById('button'), image: document.getElementById('image'), text: document.getElementById('text')};function doStuff() { image.src = 'http://some.url/image'; button.click(); console.log(text.innerHTML); // Much more logic}function removeButton() { // The button is a direct child of body. document.body.removeChild(document.getElementById('button')); // At this point, we still have a reference to #button in the global // elements dictionary. In other words, the button element is still in // memory and cannot be collected by the GC.s}
在上面这种情况中,我们对#button的保持两个引用:一个在DOM树中,另一个在elements对象中。 如果将来决定回收#button,则需要使两个引用均不可访问。在上面的代码中,由于我们只清除了来自DOM树的引用,所以#button仍然存在内存中,而不会被GC。
场景二: 如果我们想要回收某个table,但我们保持着对这个table中某个单元格(cell)的引用,这个时候将导致整个table都保存在内存中,无法GC。
闭包(Closure):闭包是一个函数,它可以访问那些定义在它的包围作用域(Enclosing Scope)里的变量,即使这个包围作用域已经结束。因此,闭包具有记忆周围环境(Context)的功能。
场景举例:
var newElem;function outer() { var someText = new Array(1000000); var elem = newElem; function inner() { if (elem) return someText; } return function () {}; }setInterval(function () { newElem = outer();}, 5);
在这个例子中,有两个闭包:一个是inner,另一个是匿名函数function () {}
。其中,inner闭包引用了someText和elem,并且,inner永远也不会被调用。可是,我们需要注意:相同父作用域的闭包,他们能够共享context。 也就是说,在这个例子中,inner的someText和elem将和匿名函数function () {}
共享。然而,这个匿名函数之后会被return返回,并且赋值给newElem。只要newElem还引用着这个匿名函数,那么,someText和elem就不会被GC。
同时,我们还要注意到,outer函数内部执行了var elem = newElem;
,而这个newElem引用了上一次调用的outer返回的匿名函数。试想,第n次调用outer将保持着第n-1次调用的outer中的匿名函数,而这个匿名函数由保持着对elem的引用,进而保持着对n-2次的...因此,这将造成内存泄漏。
解決策: setInterval のパラメーター 1 のコードを newElem = inner()();
このセクションの詳細な分析については、資料 1 と情報を参照してください。 2.
Chrome (最新バージョン 86) 開発者ツールに関する 2 つの分析ツールメモリ:
以上がJavaScript でよくあるメモリ リークの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。