JavaScriptメモリメカニズム


概要
各プログラミング言語にはメモリ管理メカニズムがあります.例えば、簡単なCにはmalloc()、free()のような低レベルのメモリ管理ベースがあります.同様にJavaScriptを学習する際には、JavaScriptのメモリ管理メカニズムを理解する必要があります.JavaScriptのメモリ管理メカニズムは、 ( , ) , “ ” 。 。この「自動」がJavaScriptに混同され、開発者は、メモリ管理を考えなくてもいいと錯覚しています.フロントエンドの開発にとって、メモリ空間は常に取り上げられている概念ではなく、無視されがちです.もちろん私自身も含まれています.長い間、メモリ空間の概念はJSの勉強ではそれほど重要ではないと思っていましたが、後で振り返ってみました.JSの基礎を再整理したところ、それらのあいまいな認識によって、多くのことが理解できなくなったことがわかりました.例えば、最も基本的な参照データ型と参照伝達はいったいどういうことですか.たとえば、浅いレプリケーションと深いレプリケーションの違いは何ですか?閉包、プロトタイプなどもあります.しかし、JavaScriptを使用して開発を行う過程で、JavaScriptメモリメカニズムを理解することは、開発者が自分が書いたコードが実行中に何が起こったのかを明確に認識し、プロジェクトのコード品質を高めるのに役立ちます.
メモリモデル
JSメモリ空間は (stack), (heap),プールに分けられる(一般的にスタックに分類されることもある).そのうち , ,プール格納定数.
ベースデータ型とスタックメモリ
JSにおける , , (閉パッケージを除く)は、システムによって自動的に記憶領域が割り当てられる. ,従って データの における記憶は、使用形態とデータ構造における に類似しており、 の原則に従う.基礎データ型:Number String Null Undefind Boolean
参照データ型とスタックメモリ
他の言語と異なり、JSの参照データ型、例えば配列Arrayは、値の大きさが固定されていない. . JS , .オブジェクトを操作する場合、実際には実際のオブジェクトではなくオブジェクトの参照を操作します.したがって、 .ここでの参照は、スタックメモリの実際の値に関連付けられたスタックメモリに保存されたアドレスとして粗浅に理解できる.データを積み上げる方法は、本棚や本とよく似ています. , , .
変数名
オカレンス
c
0x0012ff7d
b
0x0012ff7c
a3
null
a2
this is string
a1
0
メモリのライフサイクル
JS環境で割り当てられたメモリには、一般的に次のライフサイクルがあります.
  • メモリ割当て:変数、関数、オブジェクトを宣言すると、自動的にメモリが割り当てられます
  • メモリ使用:読み書きメモリ、すなわち変数、関数等
  • メモリ回収:使用済み、ゴミ回収メカニズムにより使用されなくなったメモリを自動的に回収
  • 理解を容易にするために,この周期を説明するために簡単な例を用いた.
    var a = 20;  //              
    alert(a + 100);  //     
    var a = null; //       ,      
    

    メモリ回収JavaScript では、この自動ごみ収集メカニズムの原理は何でしょうか.実はとても簡単で、 , 。 です.JavaScriptでは、タグクリアのアルゴリズムによって使用されなくなったオブジェクトを見つけるのが最も一般的であるため、a = nullは参照を解放する操作を行っただけで、a元の対応する値が参照を失い、実行環境から離れ、この値は次のゴミ収集器が操作を実行するときに発見され、解放される.適切なタイミングで参照を解除することは、ページのパフォーマンスを向上させる重要な方法です.
    局所役割ドメインでは,関数の実行が完了すると局所変数も存在する必要がないため,ゴミ収集器は判断して回収しやすい.しかし,グローバル変数がいつメモリ領域を自動的に解放する必要があるかは判断しにくい, ,.
    GoogleのV 8エンジンを例にとると、V 8エンジンではすべてのJAVASCRITTオブジェクトがスタックによってメモリ割り当てされています.コードに変数を宣言して値を割り当てると、V 8エンジンはスタックメモリにこの変数の一部を割り当てます.この変数を格納するために申請されたメモリが不足している場合、V 8エンジンは、スタックのサイズがV 8エンジンのメモリ上限に達するまでメモリを申請し続けます( ,V8 64 1464MB, 32 732MB).
    また、V 8エンジンは、スタックメモリ内のJAVASSCRIPTオブジェクトを世代別に管理する.新生代:新生代、すなわち生存周期の短いJAVASCRITTオブジェクト、例えば一時変数、文字列など;老生代:老生代は複数回のごみ回収を経ても生存し、生存周期が長いオブジェクト、例えばメインコントローラ、サーバーオブジェクトなどである.
    以下のコードで、ゴミ回収を分析します.
    function fun1() {
        var obj = {name: 'csa', age: 24};
    }
     
    function fun2() {
        var obj = {name: 'coder', age: 2}
        return obj;
    }
     
    var f1 = fun1();
    var f2 = fun2();
    

    上記のコードでは、var f1 = fun1();を実行すると、実行環境は{name:'csa', age:24}というオブジェクトを作成し、var f2 = fun2();を実行すると、実行環境は{name:'coder', age=2}というオブジェクトを作成し、次のゴミ回収が来ると{name:'csa', age:24}というオブジェクトのメモリは解放されますが、{name:'coder', age:2}というオブジェクトのメモリは解放されません.これは、fun2()関数で{name:'coder, age:2'}というオブジェクトを返し、その参照をf2変数に割り当て、またf2というオブジェクトがグローバル変数であるため、ページがアンインストールされていない場合、f2が指すオブジェクト{name:'coder', age:2}は回収されないからである.
    ごみ回収アルゴリズム
    ごみ回収アルゴリズムにとって、メモリが使用されなくなったことをどのように判断するかが核心です.
    リファレンスカウントアルゴリズム
    リファレンスカウントアルゴリズムでは、メモリが使用されなくなったことを定義する基準は簡単です.オブジェクトにリファレンスがあるかどうかを確認します.他のオブジェクトが指定されていない場合は、オブジェクトはもう必要ありません.
    例:
    //       person,        age name   
    var person = {
        age: 12,
        name: 'aaaa'
    };
    
    person.name = null; //      null,   person      name   ,  name    
    
    var p = person; 
    person = 1;         //   person      1,       p   person  ,        
    
    p = null;           // person        ,      
    

    以上から,参照カウントアルゴリズムは単純で効率的なアルゴリズムであることがわかる.しかし、循環参照という致命的な問題があります.2つのオブジェクトが互いに参照されている場合、使用されなくなったにもかかわらず、ゴミ回収器は回収されず、メモリが漏洩します.
    タイトルタグクリアアルゴリズム
    現代のブラウザでは、リファレンスカウントアルゴリズムは使用されなくなりました.現代のブラウザで一般的な多くは、タグクリアアルゴリズムに基づくいくつかの改良アルゴリズムであり、全体的な考えは一致している.タグクリアアルゴリズムは、[使用されなくなったオブジェクト](Unused Objects)を[到達できないオブジェクト](Unreachable Objects)と定義します.簡単に言えば、メモリ内のオブジェクトをルート( JS )からタイミング的にスキャンします.ルートから届くオブジェクトは、まだ使用する必要があります.ルートから触れられないオブジェクトは、使用しないとマークされ、後で回収されます.
    メモリ管理に優しいJSコードはどのように書きますか?
    古いブラウザと互換性が必要な場合は、コード内のループリファレンスの問題に注意する必要があります.あるいは、互換性を保証するライブラリを直接採用してコードの最適化を支援します.現代のブラウザで唯一注意しなければならないのは、回収する対象と根元のつながりを明確に切断することです.このような関連は明らかではなく,タグクリアアルゴリズムの強さのため,この問題は少ない場合がある.最も一般的なメモリ漏洩は、一般的にDOM要素のバインドに関連しています.
    email.message = document.createElement(“div”);
    displayList.appendChild(email.message);
    
    //    displayList   DOM  
    displayList.removeAllChildren();
    

    div要素はDOMツリーから除去され、つまりDOMツリーの根元からdiv要素に触れることができなくなった.ただし、div要素はemailオブジェクトもバインドされていることに注意してください.したがって、emailオブジェクトがまだ存在する限り、div要素はメモリに保存されます.
    小結
    参照にJSインタラクションが少量しか含まれていない場合は、メモリ管理があまり問題になりません.大規模なSPAやサーバ、デスクトップのアプリケーションの構築を開始すると、メモリの漏洩をスケジュールに上げる必要があります.実行可能なプログラムを書くことに満足しないでください.機械のアップグレードがすべてを解決できるとは思わないでください.