JSシリーズのガベージコレクションの仕組み、メモリリーク、クロージャが紙1枚でわかる(3)

coldplay.xixi
リリース: 2020-09-30 16:39:00
転載
1963 人が閲覧しました

javascriptこのコラムでは、ガベージ コレクションのメカニズム、メモリ リーク、クロージャの内容について紹介します。ファストエンド ベンチを見てみましょう。

JSシリーズのガベージコレクションの仕組み、メモリリーク、クロージャが紙1枚でわかる(3)

先頭に書く: これは、javascript 列で主に書き始めようとしているシリーズです。時代の中で、仕事や面接、技術向上のためにフレームワークを使っているとはいえ、JSの基礎知識はおまけであり、学ばなければいけない知識でもあります。車を運転するのに車について詳しく知る必要はなく、車の一般的な使い方をマスターするだけで十分です。しかし、車の知識があれば、同様に、より上手に運転することができます。もちろん、記事は一つの知識だけを語るのではなく、関連する知識が連続してつながっていくのが一般的で、自分の学びを記録しながら、自分の学びを共有し、励まし合いましょう!できれば、「いいね」もお願いします。あなたの「いいね」が更新の励みにもなります。

概要

  • 食事時間: 6〜12分
  • 難易度: 簡単、走らずに、帰る前に見てください。
##ガベージコレクションの仕組み

前回のブログでは主にメモリの割り当てと使い方(スタックメモリとヒープメモリ、ディープコピーとシャローコピー)について説明しました。未使用のメモリは、携帯電話上の未使用のソフトウェアをバックグラウンドから消去するようなもので、携帯電話の動作速度を向上させることができます。そうしないと、メモリの使用量が増えると、遅かれ早かれスタックしてしまいます。

JS についても同様です。

JSガベージ コレクター は、公園の警備パトロールと同じように、変数を「パトロール」し、関係のない人はすぐに立ち去ることができます。変数が不要になった場合、その変数が占有していたメモリ領域を解放します。このプロセスは ガベージ コレクション

JS と呼ばれます。リサイクル アルゴリズム、参照カウント、およびマークのクリア。

  • 参照カウント メソッド

    参照カウント メソッドは、最も基本的なガベージ コレクション アルゴリズムであり、最新のブラウザで使用されています。装備は撤去されました。参照カウント方法を学ぶ前に、まず

    reference という特定の概念を理解する必要があります。これは、現在の変数が指すメモリ アドレスの記述として考えることができ、メモリに似ています。 JS 参照データ型のポインター。概念を理解するために、まずコード行を見てみましょう:

    var obj={name:'jack'};复制代码
    ログイン後にコピー

    値を

    obj に割り当てると、実際には が作成されます。 Reference 変数を指します。参照カウントは 1、 参照カウントのメカニズムでは、メモリ内の各値は参照カウント

    に対応します。値を

    obj に代入すると になります null の場合、この変数は無駄なメモリになります このとき obj の参照数は になります0, そしてそれはガベージコレクションされます. obj が占有しているメモリ空間は解放されます

    関数スコープのライフサイクルは非常に短いことがわかっています. 関数の実行後が実行されると、変数内のメモリ空間は基本的には役に立たない変数です。これらをクリアしないと、メモリのゴミが解放されず、元のメモリを占有したまま解放されないため、

    メモリ リークが発生しやすくなります。 . まず、コードの一部と実行結果を見てみましょう:

    function changeName(){   var obj1={};   var obj2={};
       
       obj1.target=obj2;
       obj2.target=obj1;
       obj1.age=15;   console.log(obj1.target);   console.log(obj2.target);
    }
    
    changeName();复制代码
    ログイン後にコピー

    JSシリーズのガベージコレクションの仕組み、メモリリーク、クロージャが紙1枚でわかる(3)
    ##obj1.target
    と ## が確認できます。 #obj2.target には相互参照があります。obj1.age が変更されると、obj1.target.ageobj2.target.age が変更されるためです。も同時に影響を受け、参照カウントが一貫していることを示します。 関数が実行されると、obj1

    obj2 はまだ有効です。なぜなら obj1.targetobj2.target の実行が完了しても、参照カウントは 1 のままで、関数が実行されたことは明らかですが、このようなものこのような関数が定義されすぎているため、メモリリークこれも避けられません

    マーククリア方法
  • デメリット上記の参照カウント方法はすでに明らかなので、ここではマーキングのクリア方法について説明します。そのような問題はありません。判定基準はオブジェクト

    に到達できるかどうかなので、主に

    マーキングステージ

    クリアステージ:##の2つのステージに分かれます。 #マーキング フェーズ

    ガベージ コレクターはルート オブジェクト (Window オブジェクト) から開始し、到達可能なすべてのオブジェクトをスキャンします。これはいわゆる
      reachable
    • クリアフェーズ スキャン中に、ルート オブジェクトが到達できないオブジェクト (unreachable

      ) は不要とみなされ、ガベージとしてクリアされます

    现在再来看下上面的代码

    function changeName(){    var obj1={};  var obj2={};
      
      obj1.target=obj2;
      obj2.target=obj1;
      obj1.age=15;  console.log(obj1.target);  console.log(obj2.target);
    }
    
    changeName();复制代码
    ログイン後にコピー

    在函数执行完毕之后,函数的声明周期结束,那么现在,从 Window对象 出发, obj1obj2 都会被垃圾收集器标记为不可抵达,这样子的情况下,互相引用的情况也会迎刃而解。

内存泄漏

该释放的内存垃圾没有被释放,依然霸占着原有的内存不松手,造成系统内存的浪费,导致性能恶化,系统崩溃等严重后果,这就是所谓的内存泄漏

闭包

  • 定义与特性

    闭包是指有权访问另一个函数作用域中的变量的函数。至于为什么有权访问,主要是因为作用域嵌套作用域,也就是所谓的作用域链,关于作用域链不清楚的可以看我的第一篇博客一文搞懂JS系列(一)之编译原理,作用域,作用域链,变量提升,暂时性死区,就是因为作用域链的存在,所以内部函数才可以访问外部函数中定义的变量 ,作用域链是向外不向内的,探出头去,向外查找,而不是看着锅里,所以外部函数是无法访问内部函数定义的变量的。并且,还有一个特性就是将闭包内的变量始终保持在内存中。

    前面的作用域向外不向内,这里就不再做过多解释了,我们主要来看我后面说的特性,那就是闭包内的变量始终保存在内存中

    来看一下阮一峰教程当中的一个例子

     function f1(){     var n=999;
    
         nAdd=function(){n+=1}     function f2(){         console.log(n);
         }     return f2;
    
     } var result=f1();     //等同于return f2();
    
     result(); // 999
    
     nAdd();
    
     result(); // 1000
     nAdd();
    
     result(); // 1000复制代码
    ログイン後にコピー

    从输出结果就可以看得出来,这个变量 n 就一直保存在内存中,那么,为什么会这样子呢,我们现在就来逐步地分析代码

    ① 首先 f1() 作为 f2() 的父函数,根据作用域链的规则, nAdd() 方法以及 f2() 方法中可以正常访问到 n 的值

    f2() 被赋予了一个全局变量,可能这里大家就会开始产生疑惑了,这个 f2() 不是好好地定义在了 f1() 函数中吗,这不是扯淡吗,那么,先看下面的这句 var result=f1(); ,这个 result 很明显是被赋予了一个全局变量,这应该是没有任何争议的,那么,接着来看这个 f1() ,可以看到最后,是一句 return f2; ,看到这里,想必大家也已经想明白了,这个 f2() 被赋予了一个全局变量

    ③ 已经明白了上面的这一点以后,根据上面垃圾回收机制所提及到的标记清除法,这个 f2() 始终是可以被根对象 Window 访问到的,所以 f2 将始终存在于内存之中,而 f2 是依赖于 f1 ,因此 f1 也将始终存在于内存当中,那么, n 的值也就自然始终存在于内存当中啦

    ④ 还有一点需要注意的就是为什么我们可以直接执行 nAdd() ,这是因为在 nAdd() 的前面没有使用 var ,因此 nAdd() 是一个全局函数而不是局部函数

    所以,闭包的变量会常驻内存,滥用闭包容易造成内存泄漏,特别是在 IE 浏览器下,2020年了,应该没人使用 IE 了吧(小声bb),解决办法就是在退出函数之前,将不使用的局部变量全部删除,这也是上面讲了垃圾回收机制 => 内存泄漏,再讲到闭包的原因,我会尽量将有关联性的知识点一起讲了,也方便大家学习和加深印象。

系列目录

相关免费学习推荐:javascript(视频)

以上がJSシリーズのガベージコレクションの仕組み、メモリリーク、クロージャが紙1枚でわかる(3)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:juejin.im
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート