ホームページ  >  記事  >  ウェブフロントエンド  >  V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

青灯夜游
青灯夜游転載
2022-04-27 20:44:483006ブラウズ

この記事では、V8 エンジンのメモリ管理とガベージ コレクション アルゴリズムについて説明します。お役に立てば幸いです。

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

ご存知のとおり、JS はガベージ コレクションを自動的に管理するため、開発者はメモリの割り当てやリサイクルについて気にする必要はありません。さらに、ガベージ コレクション メカニズムも、フロントエンドのインタビューで一般的にテストされる部分です。この記事では主に V8 の世代別ガベージ コレクション アルゴリズムについて説明します。この記事を読んだ友人が V8ガベージ コレクションの仕組みについて 痛いを感じてくれれば幸いです (笑、## です) #painful!!!)、この記事では主に次の内容について説明します:

  • V8メモリの制限と解決策
  • 新世代のメモリ オブジェクト
  • Scavengeアルゴリズム
  • 到達可能性分析アルゴリズムに基づく存続オブジェクトをマークするためのロジックおよび最適化方法
  • 新世代メモリ オブジェクトの昇格条件
  • Scavengeアルゴリズムの深さ/幅優先の違い
  • 世代間のメモリ書き込みバリア
  • 旧世代のメモリ オブジェクトのマーク消去/整理アルゴリズム
  • GCSTW原因と最適化戦略

V8 のメモリ制限と解決策

V8 は当初ブラウザ用に設計されていました, 大規模なメモリが使用されるシナリオは少なくなります。設計ではデフォルトでメモリ使用量に制限があり、メモリの一部のみの使用が許可されます。64 ビット システムでは約 1.4 g のメモリが許容され、32 ビット システムでは約 1.4 g のメモリが許容されます。 -bitシステムでは約0.7gのメモリが可能です。次のコードに示すように、ノードで依存する V8 エンジンのメモリ制限メソッドを確認します。

process.memoryUsage();

// 返回内存的使用量,单位字节
{
  rss: 22953984,
  // 申请的总的堆内存
  heapTotal: 9682944,
  // 已使用的堆内存
  heapUsed: 5290344,
  external: 9388
}

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

V8メモリを制限する別の方法があります。メモリ使用量のサイズ 重要な理由は、ヒープ メモリが大きすぎると、V8 がガベージ コレクションの実行に長い時間がかかることです (1.5g には 50ms かかります)。非増分ガベージ コレクションの実行には時間がかかります (1.5g から 1s)。 V8 のガベージコレクションの仕組みについては後ほど説明すると、皆さんもより共感できると思います。

V8 エンジンにはメモリ使用量の制限がありますが、メモリ制限を変更する方法も公開されています。これは、V8 エンジンの起動時に関連パラメータを追加することです。次のコードは、Node の依存する V8 エンジン メモリ制限を変更するで説明されています:

# 更改老生代的内存限制,单位mb
node --max-old-space-size=2048 index.js

# 更改新生代的内存限制,单位mb
node --max-semi-space-size=1024=64 index.js

ここで、変更された新世代メモリの構文に注意してください。が上記の書き方に変更され、単位も

kb から mb に変更されました。以前の書き方は node --max-new-space- です。 size。次のコマンドを使用して現在の ## をクエリできます。#NodeEnvironment を使用して、新しい世代のメモリの構文を変更します: <pre class="brush:js;toolbar:false;">node --v8-options | grep max</pre>

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

V8 ガベージ コレクション戦略

エンジン内の自動ガベージ コレクション リサイクル メカニズムの歴史的進化の中で、あらゆるシナリオでガベージ コレクションを解決できる普遍的なアルゴリズムが存在しないことがわかりました。したがって、最新のガベージ コレクション アルゴリズム

は、オブジェクトの

生存時間 に基づいてメモリ ガベージを世代に分割します。 世代別ガベージ コレクション アルゴリズム は、メモリ ガベージの種類ごとに異なるメソッドを実装します。リサイクル アルゴリズム。 V8

メモリを 2 つのタイプに分割します:

新しい世代 古い世代 : 新しい世代では世代メモリ 旧世代メモリ内のオブジェクトの生存期間は短くなります。

    旧世代メモリ内の世代オブジェクトの生存期間は長いか、メモリ内に常駐します。
  • 新しい世代メモリ内のオブジェクトの生存期間は長くなります。次の図に示すように、世代メモリは新世代メモリ空間 (
  • semispace
) に格納され、古い世代メモリは旧世代メモリ空間 (

oldspace) に格納されます。

##新入生世代のメモリは V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょうScavenge

アルゴリズムを使用します
  • 旧世代のメモリは Mark-スイープ を使用し、
  • Mark-Compact
  • アルゴリズム Scavenge
  • のアルゴリズム ロジックを見てみましょう!

スカベンジ アルゴリズム

新世代メモリのメモリ リサイクルには、Scavenge アルゴリズムが使用されます。 # は

Cheney

アルゴリズムです。 Cheneyアルゴリズムは、新世代のメモリ空間を 2 つに分割し、1 つの空間は使用中 (FromSpace)、もう 1 つの空間はアイドル状態 (ToSpace# と呼ばれます) にします。 ##) 。 <p>在内存开始分配时,首先在<code>FromSpace中进行分配,垃圾回收机制执行时会检查FromSpace中的存活对象,存活对象会被会被复制到ToSpace,非存活对象所占用的空间将被释放,复制完成后FromSpaceToSpace的角色将翻转。当一个对象多次复制后依然处于存活状态,则认为其是长期存活对象,此时将发生晋升,然后该对象被移动到老生代空间oldSpace中,采用新的算法进行管理。

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

Scavenge算法其实就是在两个空间内来回复制存活对象,是典型的空间换时间做法,所以非常适合新生代内存,因为仅复制存活的对象且新生代内存中存活对象是占少数的。但是有如下几个重要问题需要考虑:

  • 引用避免重复拷贝

假设存在三个对象temp1、temp2、temp3,其中temp2、temp3都引用了temp1,js代码示例如下:

var temp2 = {
  ref: temp1,
}

var temp3 = {
  ref: temp1,
}

var temp1 = {}

FromSpace中拷贝temp2ToSpace中时,发现引用了temp1,便把temp1也拷贝到ToSpace,是一个递归的过程。但是在拷贝temp3时发现也引用了temp1,此时再把temp1拷贝过去则重复了。

要避免重复拷贝,做法是拷贝时给对象添加一个标记visited表示该节点已被访问过,后续通过visited属性判断是否拷贝对象。

  • 拷贝后保持正确的引用关系

还是上述引用关系,由于temp1不需要重复拷贝,temp3被拷贝到ToSpace之后不知道temp1对象在ToSpace中的内存地址。

做法是temp1被拷贝过去后该对象节点上会生成新的field属性指向新的内存空间地址,同时更新到旧内存对象的forwarding属性上,因此temp3就可以通过旧temp1forwarding属性找到在ToSpace中的引用地址了。

内存对象同时存在于新生代和老生代之后,也带来了问题:

  • 内存对象跨代(跨空间)后如何标记
const temp1 = {}

const temp2 = {
  ref: temp1,
}

比如上述代码中的两个对象temp1temp2都存在于新生代,其中temp2引用了temp1。假设在经过GC之后temp2晋升到了老生代,那么在下次GC的标记阶段,如何判断temp1是否是存活对象呢?

在基于可达性分析算法中要知道temp1是否存活,就必须要知道是否有根对象引用引用了temp1对象。如此的话,年轻代的GC就要遍历所有的老生代对象判断是否有根引用对象引用了temp1对象,如此的话分代算法就没有意义了。

解决版本就是维护一个记录所有的跨代引用的记录集,它是写缓冲区的一个列表。只要有老生代中的内存对象指向了新生代内存对象时,就将老生代中该对象的内存引用记录到记录集中。由于这种情况一般发生在对象写的操作,顾称此为写屏障,还一种可能的情况就是发生在晋升时。记录集的维护只要关心对象的写操作和晋升操作即可。此是又带来了另一个问题:

  • 每次写操作时维护记录集的额外开销

优化的手段是在一些Crankshaft操作中是不需要写屏障的,还有就是栈上内存对象的写操作是不需要写屏障的。还有一些,更多的手段就不在这里过多讨论。

  • 缓解Scavenge算法内存利用率不高问题

新生代内存中存活对象占比是相对较小的,因此可以在分配空间时,ToSpace可以分配的小一些。做法是将ToSpace空间分成S0S1两部分,S0用作于ToSpaceS1与原FromSpace合并当成FromSpace

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

Scavenge算法中深度/广度优先的区别

垃圾回收算法中,识别内存对象是否是垃圾的机制一般有两种:引用计数基于可达性分析

到達可能性分析に基づいて、すべての ルート参照 (グローバル変数など) を検索し、すべてのルート参照、再帰的ルート参照上のすべての参照を走査します。走査されるものはすべて ライブ オブジェクト を指定してマークします。この時点では、空間内の他のメモリ オブジェクトは デッド オブジェクトであるため、有向グラフが構築されます。

再帰の制限を考慮して、再帰ロジックは通常、非再帰実装を採用します。一般的なものには、幅優先アルゴリズムと深さ優先アルゴリズムが含まれます。 2 つの違いは次のとおりです。

  • は、深さ優先で ToSpace にコピーするときにメモリ オブジェクトの順序を変更し、参照関係を持つオブジェクトを近づけます。その理由は、自身をコピーした後、自身が参照するオブジェクトが直接コピーされるため、関連するオブジェクトが ToSpace
  • で近くにあるためです。深さの優先順位はちょうど逆です。

CPU のキャッシュ戦略により、メモリ オブジェクトを読み取るとき、より速くキャッシュにアクセスするために、その背後にあるオブジェクトが一緒に読み取られる可能性が高くなります。コード開発中の非常に一般的なシナリオは obj1.obj2.obj3 であるため、このとき、CPU が obj1 を読み取ると、次の obj2 であれば、 obj3 も一緒に読み込むとキャッシュにヒットするので非常に助かります。

したがって、深さ優先アルゴリズムは、ビジネス ロジックがキャッシュにヒットするのに役立ちますが、その実装には、メモリ領域を消費する追加のスタック支援アルゴリズムの実装が必要です。逆に、幅優先ではキャッシュ ヒットを改善することはできませんが、その実装ではポインタを使用してスペースの消費を巧みに回避でき、アルゴリズムの実行効率が高くなります。

新世代のメモリ オブジェクトの昇格条件

新世代のメモリ オブジェクトを旧世代に昇格させる場合は、次の条件を満たす必要があります。

  • オブジェクトが経験済みかどうかScavengeRecycling
  • ToSpaceメモリ使用率が制限を超えることはできません
#経験済みかどうかを判断する

Scavenge の GC のロジックは、GC のたびに生き残ったオブジェクトの age 属性を与えることです 1 、そして GC## が再度実行されたとき # のときの age 属性を判断するだけです。基本的なプロモーション図は次のとおりです。

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう旧世代のメモリには長期にわたって存続するオブジェクトが多数あり、

Scavenge

アルゴリズムが使用される理由リサイクルできないのは次のとおりです:

生き残るオブジェクトが増えるとコピー効率が低下します
  • メモリ領域の半分が無駄になります
古いリサイクル アルゴリズム世代メモリ オブジェクト

旧世代メモリ領域のガベージ コレクションは、

Mark-スイープ

(Mark-スイープ) および Mark-スイープ## を使用します。 #(Mark -Compact) の組み合わせ方法。マーキングとクリアは 2 つの部分に分かれています。 #マーキング フェーズ

    #クリア フェーズ (マーキングとソートの場合は、ソート フェーズ)
  • マーキング フェーズで古い学生を追跡する ヒープ メモリ内のすべてのメモリ オブジェクトが生成され、ライブ オブジェクトがマークされます。クリーンアップ フェーズでは、マークされていないオブジェクトのみがクリーンアップされます。その理由は、非生存オブジェクトが旧世代のメモリ内で占める割合が少数であるためです。

上図に示すように、マークのクリアの問題点の 1 つは、クリア後に使用できなくなる不連続な領域が存在するため、旧世代のメモリ クリーンアップが必要になることです。メモリ容量が必要なため、タグ付けと組み合わせたソリューション。この解決策は、マーキング プロセス中に生物オブジェクトを片側に移動し、移動の完了後に境界の外側にあるすべての非生物オブジェクトをクリーンアップして削除することです。 V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

#ガベージ コレクションの完全な一時停止V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

ガベージ コレクション中にアプリケーションの実行ロジックを一時停止し、その後アプリケーションを再開する必要があります。ガベージ コレクション メカニズムの実行ロジックが完了した後、この動作は「完全一時停止 」と呼ばれ、通常は

Stop The World

と呼ばれ、STW と呼ばれます。若い世代のメモリのガベージ コレクションはアプリケーションの実行にほとんど影響を与えませんが、旧世代のメモリには多くのオブジェクトが生き残っているため、旧世代のメモリのガベージ コレクションによって引き起こされる完全な一時停止の影響は非常に大きくなります。

GC の完全な一時停止時間を最適化するために、V8 では

incremental markV8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

concurrency mark

も導入しています。並行マーク 増分クリーニング並行クリーニング遅延クリーニングなどの方法。 STW 最適化

ガベージ コレクションに費やされた時間を測定するための重要な指標は、GC の実行中にメインスレッドが一時停止されている時間です。 。 STW の影響は許容できないため、V8 では多くの最適化手法も採用されています。

  • 並列 GC

GC プロセスは多くのことを実行する必要があり、メイン スレッドで STW 現象が発生します。並列 GC の方法は、複数の補助スレッドを開くことです。 GC 作業を共有するスレッド。このアプローチでも STW 現象を回避することはできませんが、有効な補助スレッドの数に応じて STW の合計時間を短縮できます。

1V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

    #インクリメンタル
  • GC
インクリメンタル GC は GC 作業を分割し、メインスレッドで実行します 断続的なステップ- ステップごとの実行。この方法では GC 時間は短縮されません。逆に、コストは少しかかりますが、GC の合計 STW 時間も短縮されます。

1V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

    同時実行
  • GC
同時 GC とは、GC がバックグラウンドで実行され、システム上では実行されなくなることを意味します。メインスレッド。このアプローチにより、STW 現象が回避されます。

1V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

#アイドル時間
    GC
Chrome

でのアニメーションのレンダリングはおよそです。 ##60 フレーム (各フレームは約 16ms)、現在のレンダリング時間が 16.6ms に達すると、次のような他のことを行うための自由時間が生まれます。パート番号 ##GCタスク。

#ガベージ コレクションの影響を軽減する

V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう

実行効率を向上させたい場合は、ガベージの実行と消費を最小限に抑える必要があります。 collection:

メモリをキャッシュとして使用するときは注意し、オブジェクトをキャッシュとして使用する場合にも注意してください。有効期限と無限の増大の問題を合理的に制限するには、lru 戦略を使用できます

  • ユーザー セッションを

    Node

    に保存するためにメモリを使用しないでください。そうしないと、大量のユーザー セッション オブジェクトをメモリに保存すると、古い世代のメモリが急増します。 、クリーンアップのパフォーマンスに影響を及ぼし、アプリケーションの実行パフォーマンスとメモリ オーバーフローに影響を与えます。 Redis の使用方法の改善など。キャッシュを外部に移動する利点:
  • #常駐メモリ オブジェクトの数を減らし、ガベージ コレクションをより効率的にする

    キャッシュをプロセス間で共有できる

    • ノード関連の知識については、
    • nodejs チュートリアル
    • を参照してください。

以上がV8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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