この記事では、javascript に関する関連知識を提供します。主にガベージ コレクションに関連する問題を紹介します。ガベージ コレクションは JavaScript の隠されたメカニズムです。一緒に見てみましょう。そうなることを願っています。みんなに役立つ、役に立つ。
[関連する推奨事項: JavaScript ビデオ チュートリアル、Web フロントエンド]
ガベージ コレクションは JavaScript
の隠れたメカニズムです。通常、ガベージ コレクションのために一生懸命働く必要はなく、関数の開発に集中するだけで済みます。しかし、これは、JavaScript
を書くときに座ってリラックスできるという意味ではありません。実装する関数がますます複雑になり、コードの量が蓄積するにつれて、パフォーマンスの問題がますます顕著になってきます。より高速に実行され、メモリの使用量が少なくなるコードを作成する方法は、プログラマーの終わりのない追求です。優秀なプログラマは、限られたリソースで常に驚くべき成果を上げますが、それが凡庸な存在と孤高の神との違いでもあります。
コードはコンピューターのメモリ内で実行され、コード内で定義したすべての変数、オブジェクト、関数はメモリ内の一定量のメモリ領域を占有します。コンピュータでは、メモリ スペースは非常に限られたリソースです。メモリの使用量には常に注意を払う必要があります。結局のところ、メモリ モジュールは非常に高価です。変数、関数、またはオブジェクトは、作成後に後続のコード実行に必要なくなった場合、ガベージと呼ばれる可能性があります。
ガベージの定義を直感的に理解するのは非常に簡単ですが、コンピューター プログラムの場合、現在存在する変数、関数、またはオブジェクトが、ある時点で今後使用されなくなると結論付けるのは困難です。未来。コンピュータ メモリのコストを削減し、コンピュータ プログラムを正常に実行できるようにするために、通常、次の条件のいずれかを満たすオブジェクトまたは変数はガベージであると規定します。
未参照の変数またはオブジェクトはドアのない家に相当し、決して中に入ることができないため、それらを使用することは不可能です。もう。アクセスできないオブジェクトが接続されていますが、外部からはアクセスできないため、再度使用することはできません。上記の条件を満たすオブジェクトまたは変数は、今後のプログラムの実行では二度と使用されないため、ガベージ コレクションとして安全に扱うことができます。
上記の定義で破棄すべきオブジェクトを明確にした場合、残った変数やオブジェクトにはゴミがないということでしょうか? ######いいえ!現在把握しているごみは一部であり、上記の条件を満たさないごみも残りますが、再利用することはありません。
上記の定義を満たすゴミを「絶対ゴミ」、プログラム内に隠れているそれ以外のゴミを「相対ゴミ」と言えるでしょうか?
3. ガベージ コレクション
) は、プログラムの実行中に占有された不要な変数とメモリ領域をリサイクルする役割を果たします。オブジェクトが再度使用される可能性がないにもかかわらずメモリ上に存在する現象を メモリ リーク
と呼びます。メモリ リークは、特に長時間実行されるプログラムでは非常に危険な現象です。プログラムにメモリ リークがある場合、メモリが不足するまでプログラムはさらに多くのメモリ領域を占有します。 文字列、オブジェクト、配列には固定サイズがないため、動的ストレージ割り当ては、そのサイズがわかっている場合にのみ実行できます。 JavaScript プログラムが文字列、配列、またはオブジェクトを作成するたびに、インタープリターはエンティティを保存するためにメモリを割り当てます。このようにメモリが動的に割り当てられる場合は、再度使用できるように最終的にメモリを解放する必要があります。そうしないと、JavaScript インタプリタがシステム内の利用可能なメモリをすべて消費し、システムがクラッシュする原因になります。
のガベージ コレクション メカニズムは、不要な変数やオブジェクト (ガベージ) を断続的にチェックし、それらが占有しているスペースを解放します。 4. 到達可能性
にはガベージ コレクション メカニズムがありません。すべてのメモリ管理はプログラマ独自のメモリ管理に依存しています。スキルの向上により、C
を習得するのは比較的難しいという現状があります。 JavaScript
メモリを管理するには、reachability
を使用します。文字通りに言うと、到達可能性とは、到達できることを意味します。つまり、プログラムが何らかの方法で変数やオブジェクトにアクセスして使用できることを意味します。占有メモリこれらの変数によって解放することはできません。
は、到達可能な値の固有のセットを指定しており、セット内の値は本質的に到達可能です: <ol>
<li>現在実行されている関数のコンテキスト (関数内のローカル変数、関数のパラメーターなどを含む); </li>
<li>現在のネストされた呼び出しチェーン上の他の関数、そのローカル変数とパラメータ;</li>
<li>グローバル変数;</li>
<li>その他の内部変数;</li>
</ol>
<p>上記の変数は <strong>root</strong> と呼ばれ、到達可能性ツリー。 </p>
<p>変数またはオブジェクトがルート変数によって直接的または間接的に使用されている場合、その変数は到達可能であるとみなされます。 </p>
<p>つまり、ルート (<code>A.b.c.d.e
など) を介して値にアクセスできる場合、この値に到達できます。
let people = { boys:{ boys1:{name:'xiaoming'}, boys2:{name:'xiaojun'}, }, girls:{ girls1:{name:'xiaohong'}, girls2:{name:'huahua'}, }};
上記のコードはオブジェクトを作成し、それを変数 people # に割り当てます。 ##、変数
people には 2 つのオブジェクト
boys と
girls、
boys と
girls が含まれています。サブオブジェクト。これにより、以下に示すように、
3 レイヤー参照関係を含むデータ構造も作成されます (基本タイプ データは考慮されません)。
people
boys ノードと
girls ノードはグローバル変数によって直接参照されるため、間接的に到達可能です。 boys1
、boys2
、girls1
、および girls2
はグローバル変数によって間接的に適用され、people.boys.boys を介して渡すことができます。
Access なので、到達可能な変数でもあります。 上記のコードの後に次のコードを追加すると:
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">people.girls.girls2 = null;people.girls.girls1 = people.boys.boys2;</pre><div class="contentsignin">ログイン後にコピー</div></div>
すると、上記の参照階層図は次の形式になります:
このうち、
girls1
とgirls2 は、
grils ノードからの切断により到達不能なノードになりました。つまり、これらはガベージ コレクション メカニズムによってリサイクルされることになります。 。 このとき、次のコードを実行すると:
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">people.boys.boys2 = null;</pre><div class="contentsignin">ログイン後にコピー</div></div>
すると、参照階層図は次の形式になります。
この時点では、参照階層図は次の形式になります。
boys ノードと
boys2 ノードは切断されていますが、
ノードと girls
ノードの間には参照関係があるため、ノード boys2
はまだ到達可能であり、ガベージ コレクション メカニズムによってリサイクルされません。 上記の関連図は、グローバル変数の同等の値が
root と呼ばれる理由を証明しています。関連図では、このタイプの値は通常、関係のルート ノードとして表示されるためです。木。
相互関係:と girls1上記のコードは、boys2let 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ログイン後にコピー
この時点で、
boys
boys2 の間の関連付けを切断すると、
delete people.boys.boys2;
の関係図になります。
彼氏の関係を断つと:
delete people.girls.girls1;
関係図は次のようになります:
boys2
とgirls1 の間には
girlfriend の関係がまだ存在しますが、boys2
は到達不能なノードになり、ゴミになります リサイクル機構が引き取ります。 アクセス可能な島:
<div class="code" style="position:relative; padding:0px; margin:0px;"><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><div class="contentsignin">ログイン後にコピー</div></div>
上記のコードによって形成される参照階層図は次のとおりです:
root
から切断されており、到達できなくなりました。6. ガベージ コレクション アルゴリズム
参照カウント
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;
以上代码在boy
和girl
之间存在相互引用,计数删掉boy
和girl
内的引用,二者对象并不会被回收。由于循环引用的存在,两个匿名对象的引用计数永远不会归零,也就产生了内存泄漏。
在C++
中存在一个智能指针(shared_ptr
)的概念,程序员可以通过智能指针,利用对象析构函数释放引用计数。但是对于循环引用的状况就会产生内存泄漏。
好在JavaScript
已经采用了另外一种更为安全的策略,更大程度上避免了内存泄漏的风险。
标记清除(mark and sweep
)是JavaScript
引擎采取的垃圾回收算法,其基本原理是从根出发,广度优先遍历变量之间的引用关系,对于遍历过的变量打上一个标记(优秀员工徽章
),最后删除没有标记的对象。
算法基本过程如下:
2
步,直至无新的优秀员工加入;举个栗子:
如果我们程序中存在如下图所示的对象引用关系:
我们可以清晰的看到,在整个图片的右侧存在一个“可达孤岛”,从根出发,永远无法到达孤岛。但是垃圾回收器并没有我们这种上帝视角,它们只会根据算法会首先把根节点打上优秀员工标记。
然后从优秀员工出发,找到所有被优秀员工引用的节点,如上图中虚线框中的三个节点。然后把新找到的节点同样打上优秀员工标记。
反复执行查找和标记的过程,直至所有能找到的节点都被成功标记。
最终达到下图所示的效果:
由于在算法执行周期结束之后,右侧的孤岛仍然没有标记,因此会被垃圾回收器任务无法到达这些节点,最终被清除。
如果学过数据结构和算法的童鞋可能会惊奇的发现,这不就是图的遍历吗,类似于连通图算法。
垃圾回收是一个规模庞大的工作,尤其在代码量非常大的时候,频繁执行垃圾回收算法会明显拖累程序的执行。JavaScript
算法在垃圾回收上做了很多优化,从而在保证回收工作正常执行的前提下,保证程序能够高效的执行。
性能优化采取的策略通常包括以下几点:
JavaScript
程序在执行过程中会维持相当量级的变量数目,频繁扫描这些变量会造成明显的开销。但是这些变量在生命周期上各有特点,例如局部变量会频繁的创建,迅速的使用,然后丢弃,而全局变量则会长久的占据内存。JavaScript
把两类对象分开管理,对于快速创建、使用并丢弃的局部变量,垃圾回收器会频繁的扫描,保证这些变量在失去作用后迅速被清理。而对于哪些长久把持内存的变量,降低检查它们的频率,从而节约一定的开销。
增量式的思想在性能优化上非常常见,同样可以用于垃圾回收。在变量数目非常大时,一次性遍历所有变量并颁发优秀员工标记显然非常耗时,导致程序在执行过程中存在卡顿。所以,引擎会把垃圾回收工作分成多个子任务,并在程序执行的过程中逐步执行每个小任务,这样就会造成一定的回收延迟,但通常不会造成明显的程序卡顿。
CPU
複雑なプログラムであっても、常に作業が行われるわけではありません。主な理由はCPU
作業速度が遅いためです。非常に高速ですが、ペリフェラルの IO
は多くの場合数桁遅いため、CPU
がアイドル状態のときにガベージ コレクション戦略を策定することは、非常に効果的なパフォーマンスの最適化方法であり、基本的には必要ありません。プログラム自体に悪影響を及ぼします。この戦略はシステムのアイドル時間のアップグレードに似ており、ユーザーはバックグラウンドでの実行にまったく気づきません。
この記事の主な目的は、ガベージ コレクション メカニズム、一般的に使用される戦略、最適化手法を単に廃止することです。エンジンのバックグラウンド実行原理。
この記事を通じて、次のことを理解してください:
JavaScript
の機能の 1 つであり、バックグラウンドで実行されます。心配する必要はありません; [関連する推奨事項 :JavaScript ビデオ チュートリアル 、Web フロントエンド ]
以上がJavaScriptの隠し機構のガベージコレクション知識まとめの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。