ガベージ コレクションはJavaScript
の隠されたメカニズムです。通常はガベージ コレクションについて気にする必要はなく、関数の開発に集中するだけで済みます。しかし、これは、 JavaScript
書くときに座ってリラックスできるという意味ではありません。実装する関数がますます複雑になり、コードの量が蓄積するにつれて、パフォーマンスの問題がますます顕著になります。より高速に実行され、メモリの使用量が少なくなるコードを作成する方法は、プログラマーの終わりのない追求です。優秀なプログラマは、非常に限られたリソースで常に驚くべき結果を達成できます。これは、普通の存在と孤高の神との違いでもあります。
コードとは何ですか? コンピューターのメモリで実行すると、コード内で定義したすべての変数、オブジェクト、関数がメモリ内の一定量のメモリ領域を占有します。コンピュータでは、メモリ空間は非常に限られたリソースであるため、メモリ モジュールは非常に高価です。変数、関数、またはオブジェクトは、作成後に後続のコード実行に必要なくなった場合、ガベージと呼ばれる可能性があります。
ガベージの定義を直感的に理解するのは非常に簡単ですが、コンピューター プログラムの場合、現在存在する変数、関数、オブジェクトが将来使用されなくなると、ある時点で結論付けることは困難です。コンピューターのメモリのコストを削減し、コンピューター プログラムの正常な実行を保証するために、通常、次の条件のいずれかを満たすオブジェクトまたは変数はガベージであると規定されています。
参照されていない変数またはオブジェクトは、ドアのない家と同じなので、それらを使用することはできません。アクセスできないオブジェクトが接続されていますが、外部からはアクセスできないため、再度使用することはできません。上記の条件を満たすオブジェクトまたは変数は、今後のプログラムの実行では二度と使用されないため、ガベージ コレクションとして安全に扱うことができます。
上記の定義で破棄すべきオブジェクトを明確にした場合、残った変数やオブジェクトにはゴミが存在しないということになるのでしょうか?
いいえ!我们当前分辨出的垃圾只是所有垃圾的一部分,仍然会有其他垃圾不满足以上条件,但是也不会再次被使用了。
上記の定義を満たすゴミを「絶対ゴミ」、プログラム内に隠れているそれ以外のゴミを「相対ゴミ」と言えるでしょうか?
垃圾回收机制( GC,Garbage Collection
)负责在程序执行过程中回收无用的变量和内存占用的空间。オブジェクトが再度使用される可能性がないにもかかわらずメモリ上に存在する現象をメモリ リークといいます。メモリ リークは、特に長時間実行されるプログラムでは非常に危険な現象です。プログラムにメモリ リークがある場合、メモリが不足するまでプログラムはさらに多くのメモリ領域を占有します。
文字列、オブジェクト、および配列には固定サイズがないため、それらに対する動的ストレージ割り当ては、そのサイズがわかっている場合にのみ実行できます。 JavaScript プログラムが文字列、配列、またはオブジェクトを作成するたびに、インタープリターはエンティティを保存するためにメモリを割り当てます。このようにメモリが動的に割り当てられる場合は、再度使用できるように最終的に解放する必要があります。そうしないと、JavaScript インタプリタがシステム内の利用可能なメモリをすべて消費し、システムがクラッシュします。
JavaScript
のガベージ コレクション メカニズムは、不要な変数やオブジェクト (ガベージ) を断続的にチェックし、それらが占有しているスペースを解放します。
プログラミング言語ごとに採用されるガベージ コレクション戦略は異なります。たとえば、 C++
にはガベージ コレクション メカニズムがありません。そのため、 C++
習得するのはより困難になります。 JavaScript
、到達可能性を意味します。これは、これらの変数が占めるメモリにアクセスして使用できないことを意味します。
JavaScript
specifies an inherent set of reachable values, and the values in the set are inherently reachable:
上記の変数は、到達可能性ツリーの最上位ノードと呼ばれます。
変数またはオブジェクトは、ルート変数によって直接または間接的に使用される場合、到達可能であるとみなされます。
つまり、ルート (たとえば、 Abcde
) 経由で値に到達できる場合、その値は到達可能です。
let people = { 男の子:{ ボーイズ1:{名前:'シャオミン'}、 ボーイズ2:{名前:'シャオジュン'}、 }、 女の子:{ girls1:{名前:'暁紅'}、 girls2:{名前:'フワワ'}、上記のコード
は
オブジェクトを作成し、それを変数people
に割り当てます。変数people
には、 boys
とgirls
という 2 つのオブジェクトが含まれ、 boys
とgirls
にはそれぞれ 2 つのサブオブジェクトが含まれます。これにより、以下に示すように、(基本タイプのデータに関係なく) 3
レベルの参照関係を含むデータ構造も作成されます。
このうち、 people
ノードはグローバル変数なので自然に到達できます。 boys
とgirls
ノードはグローバル変数によって直接参照されるため、間接的に到達可能です。 boys1
、 boys2
、 girls1
、 girls2
も、グローバル変数によって間接的に使用され、 people.boys.boys
を通じてアクセスできるため、到達可能な変数です。
如果我们在以上代码的后面加上以下代码:
people.girls.girls2 = null;people.girls.girls1 = people.boys.boys2;
那么,以上引用层次图将会变成如下形式:
其中, girls1
和girls2
由于和grils
节点断开连接,从而变成了不可达节点,意味着将被垃圾回收机制回收。
このとき、
people.boys.boys2 = null;というコードを実行すると
、参照階層図は次のようになります。
この時点で、 boys
ノードとboys2
ノードは切断されますが、 boys2
ノードとgirls
ノード間の参照関係により、 boys2
まだ到達可能であり、ガベージ コレクション メカニズムによってリサイクルされません。
上記の関連図は、グローバル変数に相当する値がrootと呼ばれる理由を証明しています。関連図では、このタイプの値は通常、関係ツリーのルート ノードとして表示されるためです。
people = { とします 男の子:{ ボーイズ1:{名前:'シャオミン'}、 ボーイズ2:{名前:'シャオジュン'}、 }、 女の子:{ girls1:{名前:'暁紅'}、 girls2:{名前:'フワワ'}、 }};people.boys.boys2.girlfriend = people.girls.girls1; //boys2 は girls1people.girls.girls1.boyfriend = people.boys.boys2 を参照します。
上記のコードは、 boys2
とgirls1
の間に相互関係を作成します。
この時点で、 boys
とboys2
の間の関連付けを切断すると
、オブジェクト
間の関連付け図は次のようになります。
明らかに、到達できないノードはありません。
この時点で、 boyfriend
関係の接続を切断すると、
people.girls.girls1 を削除すると、
関係図は次のようになります。
この時点では、 boys2
とgirls1
間にはまだgirlfriend
関係が存在しますが、 boys2
到達不能ノードとなり、ガベージ コレクション メカニズムによって回収されます。
people = { にします 男の子:{ ボーイズ1:{名前:'シャオミン'}、 ボーイズ2:{名前:'シャオジュン'}、 }、 女の子:{ girls1:{名前:'暁紅'}、 girls2:{名前:'フワワ'}、 }};delete people.boys;delete people.girls;
上記のコードによって形成された参照階層図は次のとおりです。
この時点では、点線のボックス内のオブジェクト間には相互参照関係がまだ存在しますが、これらのオブジェクトも到達不能となり、ガベージ コレクション メカニズムによって削除されます。これらのノードはルートとの関係を失い、到達できなくなります。
いわゆる参照カウントは、その名前が示すように、オブジェクトが参照されるたびにカウントします。参照を追加すると参照が 1 ずつ減ります。 number becomes 0, it is considered Garbage, thus deleting objects to reclaim memory.
例:
let user = {username:'xiaoming'}; //オブジェクトはユーザー変数 count +1 によって参照されます user2 = ユーザーとします。 //オブジェクトは新しい変数によって参照され、カウント+1 ユーザー = null; //变量不再引用对象,计数-1 user2 = null; //変数はオブジェクトを参照しなくなりました、奇数 -1 //この時点では、オブジェクト参照の数は 0 であるため、削除されます。
参照カウント方法は非常に合理的であるように見えますが、実際には、参照カウント方法を使用したメモリ再利用メカニズムには明らかな抜け穴があります。
例:
letboy = {}; let girl = {}; 男の子.ガールフレンド = 女の子; 女の子.ボーイフレンド = 男の子; 男の子 = null; girl = null;
以上代码在boy
和girl
之间存在相互引用,计数删掉boy
和girl
内的引用,二者对象并不会被回收。循環参照が存在するため、2 つの匿名オブジェクトの参照カウントがゼロに戻らず、メモリ リークが発生します。
C++
にはスマート ポインター( shared_ptr
) の概念があり、プログラマーはスマート ポインターを使用してオブジェクト デストラクターを使用して参照カウントを解放できます。ただし、循環参照の場合にはメモリ リークが発生します。
幸いなことに、 JavaScript
別のより安全な戦略を採用しており、メモリ リークのリスクを大幅に回避しています。
マークmark and sweep
は、 JavaScript
エンジンで採用されているガベージ コレクション アルゴリズムです。その基本原理は、ルートから開始して変数間の参照関係を幅優先で走査し、走査された変数にマーク (优秀员工徽章
) を付けることです。マークのないオブジェクトは最終的に削除されます。
アルゴリズムの基本的なプロセスは次のとおりです。
2
新しい優秀な従業員が参加しなくなるまで、例:
以下に示すように、プログラム内にオブジェクト参照関係があるとします。
全体図の右側に「到達可能な島」があることがはっきりとわかります。ルートから開始すると、その島には決して到達できません。しかし、ガベージ コレクターは私たちのような神の視点を持っておらず、アルゴリズムに基づいてルート ノードを優秀な従業員としてマークするだけです。
次に、優秀な従業員から開始して、優秀な従業員によって引用されたすべてのノード (上の図の点線のボックス内の 3 つのノードなど) を見つけます。次に、新しく見つかったノードを優秀な従業員としてマークします。
見つかったすべてのノードが正常にマークされるまで、検索とマークのプロセスが繰り返されます。
最終的に、次の図に示す効果が得られます。
右側のアイランドはアルゴリズムの実行サイクルが終了した後もマークされていないため、これらのノードはガベージ コレクター タスクによって到達できず、最終的にはクリアされます。
データ構造とアルゴリズムを学習した子供は、これが接続グラフ アルゴリズムと同様のグラフ トラバーサルであることに気づくと驚くかもしれません。
ガベージ コレクションは大規模なタスクであり、特にコードの量が非常に多い場合、ガベージ コレクション アルゴリズムを頻繁に実行すると、プログラムの実行が大幅に低下します。 JavaScript
アルゴリズムは、Garbage Collectionで多くの最適化を行い、リサイクル作業の通常の実行を保証しながらプログラムを効率的に実行できるようにしました。
性能优化采取的策略通常包括以下几点:
JavaScript
程序在执行过程中会维持相当量级的变量数目,频繁扫描这些变量会造成明显的开销。ただし、これらの変数にはライフサイクルにおける独自の特性があります。たとえば、ローカル変数は頻繁に作成され、すぐに使用されてから破棄されますが、グローバル変数は長時間メモリを占有します。 JavaScript
把两类对象分开管理,对于快速创建、使用并丢弃的局部变量,垃圾回收器会频繁的扫描,保证这些变量在失去作用后迅速被清理。メモリを長時間保持する変数の場合、それらをチェックする頻度を減らして、一定量のオーバーヘッドを節約します。
増分というアイデアはパフォーマンスの最適化において非常に一般的であり、ガベージ コレクションにも使用できます。変数の数が非常に多い場合、すべての変数を一度に調べて未処理の従業員マークを発行するのは明らかに非常に時間がかかり、プログラムの実行中に遅延が発生します。したがって、エンジンは、ガベージコレクション作業を複数のサブタスクに分割し、プログラムの実行中に各小さなタスクを徐々に実行しますが、通常は明らかなプログラムラグを引き起こしません。
CPU
does not always work even in complex programs. This is mainly because CPU
works very fast and peripheral IO
is often several orders of magnitude slower. Therefore, it is a good idea to arrange a garbage collection strategy when CPU
isこれは非常に効果的なパフォーマンス最適化方法であり、基本的にプログラム自体に悪影響を及ぼしません。这种策略就类似于系统的空闲时间升级一样,用户根本察觉不到后台的执行。
この記事の主な目的は、ガベージ コレクション メカニズム、一般的に使用される戦略、および最適化手法を単に終了することです。エンジンのバックグラウンド実行原理を深く理解することを目的としたものではありません。
この記事を通じて、次のことを理解してください。
JavaScript
の機能の 1 つであり、バックグラウンドで実行されるため、私たちがそれについて心配する必要はありません。