Jsによるメモリ漏洩のいくつかの状況

4472 ワード

紹介:
jsのメモリゴミ回収メカニズム:ゴミ回収器は定期的にメモリをスキャンし、あるメモリの値がゼロに参照されると回収します.現在の変数は使用済みですが、参照されているため、ゴミ回収器が回収できず、メモリが漏れています.従来のページはジャンプするたびにメモリが解放されるので、特に明らかではありません.
Vue単ページアプリケーション:Web Appは従来のWebとは異なり、Web Appは単ページアプリケーションページがルーティングジャンプによってページをリフレッシュしないため、メモリ漏れが絶えず蓄積し、ページカートンを招く.
漏洩点:
1.DOM/BOM対象漏れ2.scriptにDOM/BOMオブジェクトへの参照が存在するため、3.Javascriptオブジェクトの漏洩4.通常、イベント処理コールバックなどの閉パッケージによって、DOMオブジェクトとスクリプト内のオブジェクトの双方向参照が発生します.この場合、よくある漏洩の原因です.
コードの注目点:
1.DOMのaddEventLisner関数および派生イベントリスニング、例えばJqueryのon関数、vueコンポーネントインスタンスの$on関数、サードパーティライブラリの初期化関数2.他のBOMオブジェクトのイベントリスニング、例えばwebsocketインスタンスのon関数3.不要な関数参照を避ける4.render関数を使用する場合、htmlラベルにDOM/BOMイベントをバインドしないでください.
Vueはどのように処理しますか:
1.mounted/createdフックにDOM/BOMオブジェクトのイベントがバインドされている場合、beforeDestroyで対応する解縛処理を行う必要がある.mounted/createdフックでサードパーティ製ライブラリ初期化を使用する場合は、beforeDestroyで対応する破棄処理を行う必要があります.コンポーネントにタイマーが使用する場合は、beforeDestroyで対応する破棄処理を行う必要がある.テンプレートでは、式を使用して特定の処理関数にバインドしないでください.この論理は処理関数に置くべきですか?5.mounted/createdフックに$onを使用する場合、beforeDestroyで対応解縛($off)処理を行う必要がある.テンプレート内のバインドを$onで置き換えると、一部のコンポーネントがイベントバインドを使用して漏洩する可能性があります.
Vueの公式サイトはメモリの漏洩を避けることを説明しますhttps://cn.vuejs.org/v2/cookbook/avoiding-memory-leaks.html
また、vueはIE edgeブラウザの下で、親子コンポーネントのシーンで、子コンポーネントは親コンポーネントの状態に依存し、子コンポーネントは親コンポーネントの状態変化を制御して子コンポーネントの展示変化にフィードバックし、子コンポーネントはv-ifモードでビューに存在し、親コンポーネントは状態制御で子コンポーネントのv-if状態変換を制御する.サブコンポーネントは、親コンポーネントのステータスを制御してサブコンポーネントのデータ入力が完了すると、親コンポーネントはサブコンポーネントのv-ifステータスを切り替え、サブコンポーネントがdom構造を占有してクリーンアップされます.このとき、サブコンポーネントが存在する場合のメモリ消費量は解放されず、親コンポーネントが再びv-if状態に戻ると、サブコンポーネントが再表示され、メモリが急上昇し、何回かの切り替えを繰り返すと、メモリの急上昇が顕著になり、ページカートンが表示されます.
 
jsの通常のメモリ漏洩のいくつかの状況の紹介
1.閉パッケージ
function fn1(){
    var n=1;
}
//           n
function fn1(){
    var n=1;
    function fn2(){//    fn2     
        alert(n);
    }

}

でも外ではまだアクセスできないのでreturnが出てきます
function fn1(){
    var n=1;
    function fn2(){//    fn2     
        alert(n);
    }
return fn2(); 
//return        window          。        , IE         
}
fn1();

できるだけ書くときは、このような状況を避けます. 
2.予期せぬグローバル変数
宣言されていない変数の参照は、グローバルオブジェクトに新しい変数を作成します.ブラウザの環境では、グローバルオブジェクトはwindowです.つまり、次のようになります.
function foo(arg) {
    bar = "aaaaa";
}

      
function foo(arg) {
    window.bar = "aaaaa";
}
function foo() {
    this.variable = "qqqqq";
}
//this       (window)
foo();
 

このエラーを防ぐために、JavaScriptファイルの先頭に'use strict';文を追加できます.
3.タイマーsetTimeout setInterval
setIntervalまたはsetTimeoutを必要としない場合、タイマはclearされず、タイマのコールバック関数および内部依存変数は回収されず、メモリが漏洩する.例えば、vueはタイマーを使用しており、beforeDestroyで対応する破棄処理を行う必要があります.jsも同じです.
clearTimeout(***)
clearInterval(***)

4.mounted/createdフックに$onが使用されている場合は、beforeDestroyで対応解縛($off)処理を行う必要があります
beforeDestroy() {
  this.bus.$off('****');
}

5、DOMオブジェクトに追加した属性はオブジェクトの参照である
var testObject = {}; 
document.getElementById('idname').property = testObject;  //  DOM    , testObject     ,      

解決方法:
Windowsでonunloadイベントに次のように書きます.
window.onunload=function(){
    document.getElementById('idname').property = null;         //    
};

6.DOMオブジェクトとJSオブジェクトの相互参照
function testObject(element) { 
this.elementReference = element;    //  testObject(js)       element(DOM)  
element.property = this;      //  element(DOM)       testObject(js)  
} 
new testObject(document.getElementById('idname'));

解決方法:
Windowsでonunloadイベントに次のように書きます.
document.getElementById('idname').property = null;

7.appendChildを外部から内部へ実行します.この場合removeChildを呼び出しても解放できません
var parentDiv = document.createElement("div"); 
var childDiv = document.createElement("div"); 
document.body.appendChild(parentDiv); 
parentDiv.appendChild(childDiv); 

解決策:appendChildを内部から外部へ実行する:
var parentDiv = document.createElement("div"); 
var childDiv = document.createElement("div"); 
parentDiv.appendChild(childDiv); 
document.body.appendChild(parentDiv); 

8.同じ属性を繰り返し書き換えるとメモリが大量に消費される(ただしIEをオフにするとメモリが解放される)
for(i = 0; i < 5000; i++) { 
   hostElement.text = "asdfasdfasdf"; 
} 

この方法は5000の属性を定義したことに相当します! 
9.プログラムロジックに注意し、「デッドサイクル」などを避ける
10.echartsは循環タイマー等によるメモリリークに対応