ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScriptの隠し機構のガベージコレクション知識まとめ

JavaScriptの隠し機構のガベージコレクション知識まとめ

WBOY
WBOY転載
2022-06-08 16:11:262765ブラウズ

この記事では、javascript に関する関連知識を提供します。主にガベージ コレクションに関連する問題を紹介します。ガベージ コレクションは JavaScript の隠されたメカニズムです。一緒に見てみましょう。そうなることを願っています。みんなに役立つ、役に立つ。

JavaScriptの隠し機構のガベージコレクション知識まとめ

[関連する推奨事項: JavaScript ビデオ チュートリアルWeb フロントエンド]

1. はじめに

ガベージ コレクションは JavaScript の隠れたメカニズムです。通常、ガベージ コレクションのために一生懸命働く必要はなく、関数の開発に集中するだけで済みます。しかし、これは、JavaScript を書くときに座ってリラックスできるという意味ではありません。実装する関数がますます複雑になり、コードの量が蓄積するにつれて、パフォーマンスの問題がますます顕著になってきます。より高速に実行され、メモリの使用量が少なくなるコードを作成する方法は、プログラマーの終わりのない追求です。優秀なプログラマは、限られたリソースで常に驚くべき成果を上げますが、それが凡庸な存在と孤高の神との違いでもあります。

2. ガベージとは

コードはコンピューターのメモリ内で実行され、コード内で定義したすべての変数、オブジェクト、関数はメモリ内の一定量のメモリ領域を占有します。コンピュータでは、メモリ スペースは非常に限られたリソースです。メモリの使用量には常に注意を払う必要があります。結局のところ、メモリ モジュールは非常に高価です。変数、関数、またはオブジェクトは、作成後に後続のコード実行に必要なくなった場合、ガベージと呼ばれる可能性があります。

ガベージの定義を直感的に理解するのは非常に簡単ですが、コンピューター プログラムの場合、現在存在する変数、関数、またはオブジェクトが、ある時点で今後使用されなくなると結論付けるのは困難です。未来。コンピュータ メモリのコストを削減し、コンピュータ プログラムを正常に実行できるようにするために、通常、次の条件のいずれかを満たすオブジェクトまたは変数はガベージであると規定します。

  1. 参照されたオブジェクトまたは変数がない。
  2. アクセスできないオブジェクト (複数のオブジェクト間の循環参照);

未参照の変数またはオブジェクトはドアのない家に相当し、決して中に入ることができないため、それらを使用することは不可能です。もう。アクセスできないオブジェクトが接続されていますが、外部からはアクセスできないため、再度使用することはできません。上記の条件を満たすオブジェクトまたは変数は、今後のプログラムの実行では二度と使用されないため、ガベージ コレクションとして安全に扱うことができます。

上記の定義で破棄すべきオブジェクトを明確にした場合、残った変数やオブジェクトにはゴミがないということでしょうか? ######いいえ!現在把握しているごみは一部であり、上記の条件を満たさないごみも残りますが、再利用することはありません。

上記の定義を満たすゴミを「絶対ゴミ」、プログラム内に隠れているそれ以外のゴミを「相対ゴミ」と言えるでしょうか?

3. ガベージ コレクション

ガベージ コレクション メカニズム (

GC、ガベージ コレクション

) は、プログラムの実行中に占有された不要な変数とメモリ領域をリサイクルする役割を果たします。オブジェクトが再度使用される可能性がないにもかかわらずメモリ上に存在する現象を メモリ リーク と呼びます。メモリ リークは、特に長時間実行されるプログラムでは非常に危険な現象です。プログラムにメモリ リークがある場合、メモリが不足するまでプログラムはさらに多くのメモリ領域を占有します。 文字列、オブジェクト、配列には固定サイズがないため、動的ストレージ割り当ては、そのサイズがわかっている場合にのみ実行できます。 JavaScript プログラムが文字列、配列、またはオブジェクトを作成するたびに、インタープリターはエンティティを保存するためにメモリを割り当てます。このようにメモリが動的に割り当てられる場合は、再度使用できるように最終的にメモリを解放する必要があります。そうしないと、JavaScript インタプリタがシステム内の利用可能なメモリをすべて消費し、システムがクラッシュする原因になります。

JavaScript

のガベージ コレクション メカニズムは、不要な変数やオブジェクト (ガベージ) を断続的にチェックし、それらが占有しているスペースを解放します。 4. 到達可能性

異なるプログラミング言語は異なるガベージ コレクション戦略を採用しています。たとえば、

C

にはガベージ コレクション メカニズムがありません。すべてのメモリ管理はプログラマ独自のメモリ管理に依存しています。スキルの向上により、C を習得するのは比較的難しいという現状があります。 JavaScriptメモリを管理するには、reachability を使用します。文字通りに言うと、到達可能性とは、到達できることを意味します。つまり、プログラムが何らかの方法で変数やオブジェクトにアクセスして使用できることを意味します。占有メモリこれらの変数によって解放することはできません。

JavaScript

は、到達可能な値の固有のセットを指定しており、セット内の値は本質的に到達可能です: <ol> <li>現在実行されている関数のコンテキスト (関数内のローカル変数、関数のパラメーターなどを含む); </li> <li>現在のネストされた呼び出しチェーン上の他の関数、そのローカル変数とパラメータ;</li> <li>グローバル変数;</li> <li>その他の内部変数;</li> </ol> <p>上記の変数は <strong>root</strong> と呼ばれ、到達可能性ツリー。 </p> <p>変数またはオブジェクトがルート変数によって直接的または間接的に使用されている場合、その変数は到達可能であるとみなされます。 </p> <p>つまり、ルート (<code>A.b.c.d.e など) を介して値にアクセスできる場合、この値に到達できます。

5. 到達可能性の例

階層的な関連付け:

let people = {
    boys:{
        boys1:{name:'xiaoming'},
        boys2:{name:'xiaojun'},
    },
    girls:{
        girls1:{name:'xiaohong'},
        girls2:{name:'huahua'},
    }};

上記のコードはオブジェクトを作成し、それを変数 people # に割り当てます。 ##、変数 people には 2 つのオブジェクト boysgirlsboysgirls が含まれています。サブオブジェクト。これにより、以下に示すように、3 レイヤー参照関係を含むデータ構造も作成されます (基本タイプ データは考慮されません)。 people

ノードはグローバル変数であるため、自然に到達可能です。

boysJavaScriptの隠し機構のガベージコレクション知識まとめ ノードと

girls

ノードはグローバル変数によって直接参照されるため、間接的に到達可能です。 boys1boys2girls1、および girls2 はグローバル変数によって間接的に適用され、people.boys.boys を介して渡すことができます。 Access なので、到達可能な変数でもあります。 上記のコードの後に​​次のコードを追加すると: <pre class="brush:php;toolbar:false">people.girls.girls2 = null;people.girls.girls1 = people.boys.boys2;</pre> すると、上記の参照階層図は次の形式になります:

このうち、

girls1

girls2JavaScriptの隠し機構のガベージコレクション知識まとめ は、

grils

ノードからの切断により到達不能なノードになりました。つまり、これらはガベージ コレクション メカニズムによってリサイクルされることになります。 。 このとき、次のコードを実行すると: <pre class="brush:php;toolbar:false">people.boys.boys2 = null;</pre>すると、参照階層図は次の形式になります。

この時点では、参照階層図は次の形式になります。

boys

ノードと
boys2JavaScriptの隠し機構のガベージコレクション知識まとめ ノードは切断されていますが、

boys2

ノードと girls ノードの間には参照関係があるため、ノード boys2 はまだ到達可能であり、ガベージ コレクション メカニズムによってリサイクルされません。 上記の関連図は、グローバル変数の同等の値が root と呼ばれる理由を証明しています。関連図では、このタイプの値は通常、関係のルート ノードとして表示されるためです。木。

相互関係:

let people = {
    boys:{
        boys1:{name:'xiaoming'},
        boys2:{name:'xiaojun'},
    },
    girls:{
        girls1:{name:'xiaohong'},
        girls2:{name:'huahua'},
    }};people.boys.boys2.girlfriend = people.girls.girls1;	
    //boys2引用girls1people.girls.girls1.boyfriend = people.boys.boys2;	//girls1引用boys2
上記のコードは、boys2

と girls1

の間に相互関連関係を作成します。関係構造図は次のとおりです。

この時点で、boys

boys2JavaScriptの隠し機構のガベージコレクション知識まとめ の間の関連付けを切断すると、

delete people.boys.boys2;

の関係図になります。

明らかに、到達できないノードはありません。

このとき、

彼氏JavaScriptの隠し機構のガベージコレクション知識まとめの関係を断つと:

delete people.girls.girls1;

関係図は次のようになります:

この時点では、

boys2

girls1JavaScriptの隠し機構のガベージコレクション知識まとめ の間には

girlfriend

の関係がまだ存在しますが、boys2 は到達不能なノードになり、ゴミになります リサイクル機構が引き取ります。 アクセス可能な島: <pre class="brush:php;toolbar:false">let people = {     boys:{         boys1:{name:'xiaoming'},         boys2:{name:'xiaojun'},     },     girls:{         girls1:{name:'xiaohong'},         girls2:{name:'huahua'},     }};delete people.boys;delete people.girls;</pre>上記のコードによって形成される参照階層図は次のとおりです:

この時点では、点線のボックス内のオブジェクト間には相互参照関係がまだ残っていますが、これらのオブジェクトも到達できなくなり、ガベージ コレクション メカニズムによって削除されます。これらのノードは

root

から切断されており、到達できなくなりました。

JavaScriptの隠し機構のガベージコレクション知識まとめ6. ガベージ コレクション アルゴリズム

参照カウント

いわゆる参照カウントとは、名前が示すように、オブジェクトが存在するたびにカウントすることです。参照されています。参照が追加されると 1 ずつ増加し、参照が削除されると 1 ずつ減ります。参照の数が 0 になると、それはガベージとみなされ、オブジェクトはメモリを再利用するために削除されます。 。

例:
let user = {username:'xiaoming'};
//对象被user变量引用,计数+1
let user2 = user;
//对象被新的变量引用,计数+1
user = null;
//变量不再引用对象,计数-1
user2 = null;
//变量不再引用对象,奇数-1
//此时,对象引用数为0,会被删除
参照カウント方法は非常に合理的であるように見えますが、実際には、参照カウント方法を使用したメモリ リサイクル メカニズムには明らかな抜け穴があります。 ######例えば:###
let boy = {};	
let girl = {};	
boy.girlfriend = girl;
girl.boyfriend = boy;
boy = null;
girl = null;

以上代码在boygirl之间存在相互引用,计数删掉boygirl内的引用,二者对象并不会被回收。由于循环引用的存在,两个匿名对象的引用计数永远不会归零,也就产生了内存泄漏。

C++中存在一个智能指针shared_ptr)的概念,程序员可以通过智能指针,利用对象析构函数释放引用计数。但是对于循环引用的状况就会产生内存泄漏。

好在JavaScript已经采用了另外一种更为安全的策略,更大程度上避免了内存泄漏的风险。

标记清除

标记清除mark and sweep)是JavaScript引擎采取的垃圾回收算法,其基本原理是从出发,广度优先遍历变量之间的引用关系,对于遍历过的变量打上一个标记(优秀员工徽章),最后删除没有标记的对象。

算法基本过程如下:

  1. 垃圾收集器找到所有的,并颁发优秀员工徽章(标记);
  2. 然后它遍历优秀员工,并将优秀员工引用的对象同样打上优秀员工标记;
  3. 反复执行第2步,直至无新的优秀员工加入;
  4. 没有被标记的对象都会被删除。

举个栗子:

如果我们程序中存在如下图所示的对象引用关系:

JavaScriptの隠し機構のガベージコレクション知識まとめ

我们可以清晰的看到,在整个图片的右侧存在一个“可达孤岛”,从出发,永远无法到达孤岛。但是垃圾回收器并没有我们这种上帝视角,它们只会根据算法会首先把根节点打上优秀员工标记。

JavaScriptの隠し機構のガベージコレクション知識まとめ

然后从优秀员工出发,找到所有被优秀员工引用的节点,如上图中虚线框中的三个节点。然后把新找到的节点同样打上优秀员工标记。

JavaScriptの隠し機構のガベージコレクション知識まとめ

反复执行查找和标记的过程,直至所有能找到的节点都被成功标记。

JavaScriptの隠し機構のガベージコレクション知識まとめ

最终达到下图所示的效果:

JavaScriptの隠し機構のガベージコレクション知識まとめ

由于在算法执行周期结束之后,右侧的孤岛仍然没有标记,因此会被垃圾回收器任务无法到达这些节点,最终被清除。

如果学过数据结构和算法的童鞋可能会惊奇的发现,这不就是图的遍历吗,类似于连通图算法。

七、性能优化

垃圾回收是一个规模庞大的工作,尤其在代码量非常大的时候,频繁执行垃圾回收算法会明显拖累程序的执行。JavaScript算法在垃圾回收上做了很多优化,从而在保证回收工作正常执行的前提下,保证程序能够高效的执行。

性能优化采取的策略通常包括以下几点:

分代回收

JavaScript程序在执行过程中会维持相当量级的变量数目,频繁扫描这些变量会造成明显的开销。但是这些变量在生命周期上各有特点,例如局部变量会频繁的创建,迅速的使用,然后丢弃,而全局变量则会长久的占据内存。JavaScript把两类对象分开管理,对于快速创建、使用并丢弃的局部变量,垃圾回收器会频繁的扫描,保证这些变量在失去作用后迅速被清理。而对于哪些长久把持内存的变量,降低检查它们的频率,从而节约一定的开销。

增量收集

增量式的思想在性能优化上非常常见,同样可以用于垃圾回收。在变量数目非常大时,一次性遍历所有变量并颁发优秀员工标记显然非常耗时,导致程序在执行过程中存在卡顿。所以,引擎会把垃圾回收工作分成多个子任务,并在程序执行的过程中逐步执行每个小任务,这样就会造成一定的回收延迟,但通常不会造成明显的程序卡顿。

アイドルコレクション

CPU複雑なプログラムであっても、常に作業が行われるわけではありません。主な理由はCPU 作業速度が遅いためです。非常に高速ですが、ペリフェラルの IO は多くの場合数桁遅いため、CPU がアイドル状態のときにガベージ コレクション戦略を策定することは、非常に効果的なパフォーマンスの最適化方法であり、基本的には必要ありません。プログラム自体に悪影響を及ぼします。この戦略はシステムのアイドル時間のアップグレードに似ており、ユーザーはバックグラウンドでの実行にまったく気づきません。

8. 概要

この記事の主な目的は、ガベージ コレクション メカニズム、一般的に使用される戦略、最適化手法を単に廃止することです。エンジンのバックグラウンド実行原理。

この記事を通じて、次のことを理解してください:

  1. ガベージ コレクションは JavaScript の機能の 1 つであり、バックグラウンドで実行されます。心配する必要はありません;
  2. ガベージ コレクションの戦略はマーク除去であり、到達可能性理論に従ってガベージをフィルタリングして削除します;
  3. クリア マーク戦略により、到達可能なアイランドによって引き起こされるメモリ リークを回避できます

[関連する推奨事項 :JavaScript ビデオ チュートリアル Web フロントエンド ]

以上がJavaScriptの隠し機構のガベージコレクション知識まとめの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。