V8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょう
この記事では、V8 エンジンのメモリ管理とガベージ コレクション アルゴリズムについて説明します。お役に立てば幸いです。
ご存知のとおり、JS はガベージ コレクションを自動的に管理するため、開発者はメモリの割り当てやリサイクルについて気にする必要はありません。さらに、ガベージ コレクション メカニズムも、フロントエンドのインタビューで一般的にテストされる部分です。この記事では主に V8 の世代別ガベージ コレクション アルゴリズムについて説明します。この記事を読んだ友人が V8
ガベージ コレクションの仕組みについて 痛い
を感じてくれれば幸いです (笑、## です) #painful!!!)、この記事では主に次の内容について説明します:
- V8
メモリの制限と解決策
新世代のメモリ オブジェクト - Scavenge
アルゴリズム
- 到達可能性分析アルゴリズムに基づく
存続オブジェクトをマークするためのロジックおよび最適化方法
新世代メモリ オブジェクトの昇格条件 - Scavenge
アルゴリズムの深さ/幅優先の違い
世代間のメモリ書き込みバリア - 旧世代のメモリ オブジェクトのマーク消去/整理アルゴリズム
- GC
STW
原因と最適化戦略
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 がガベージ コレクションの実行に長い時間がかかることです (
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。次のコマンドを使用して現在の ## をクエリできます。#Node
Environment を使用して、新しい世代のメモリの構文を変更します: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class='brush:php;toolbar:false;'>node --v8-options | grep max</pre><div class="contentsignin">ログイン後にコピー</div></div>
エンジン内の自動ガベージ コレクション リサイクル メカニズムの歴史的進化の中で、あらゆるシナリオでガベージ コレクションを解決できる普遍的なアルゴリズムが存在しないことがわかりました。したがって、最新のガベージ コレクション アルゴリズム
は、オブジェクトの生存時間 に基づいてメモリ ガベージを世代に分割します。 世代別ガベージ コレクション アルゴリズム は、メモリ ガベージの種類ごとに異なるメソッドを実装します。リサイクル アルゴリズム。 V8
メモリを 2 つのタイプに分割します:新しい世代 と
古い世代 :
新しい世代では世代メモリ 旧世代メモリ内のオブジェクトの生存期間は短くなります。
- 旧世代メモリ内の世代オブジェクトの生存期間は長いか、メモリ内に常駐します。
- 新しい世代メモリ内のオブジェクトの生存期間は長くなります。次の図に示すように、世代メモリは新世代メモリ空間 ( semispace
oldspace) に格納されます。
##新入生世代のメモリは Scavenge
- 旧世代のメモリは
Mark-スイープ
を使用し、 Mark-Compact - アルゴリズム
スカベンジ アルゴリズム
新世代メモリのメモリ リサイクルには、Scavenge アルゴリズムが使用されます。 # は
Cheney アルゴリズムです。 Cheney
アルゴリズムは、新世代のメモリ空間を 2 つに分割し、1 つの空間は使用中 (FromSpace
)、もう 1 つの空間はアイドル状態 (ToSpace# と呼ばれます) にします。 ##) 。
<p>在内存开始分配时,首先在<code>FromSpace
中进行分配,垃圾回收机制执行时会检查FromSpace
中的存活对象,存活对象会被会被复制到ToSpace
,非存活对象所占用的空间将被释放,复制完成后FromSpace
和ToSpace
的角色将翻转。当一个对象多次复制后依然处于存活状态,则认为其是长期存活对象,此时将发生晋升,然后该对象被移动到老生代空间oldSpace
中,采用新的算法进行管理。
Scavenge
算法其实就是在两个空间内来回复制存活对象,是典型的空间换时间做法,所以非常适合新生代内存,因为仅复制存活的对象且新生代内存中存活对象是占少数的。但是有如下几个重要问题需要考虑:
- 引用避免重复拷贝
假设存在三个对象temp1、temp2、temp3
,其中temp2、temp3
都引用了temp1
,js代码示例如下:
var temp2 = { ref: temp1, } var temp3 = { ref: temp1, } var temp1 = {}
从FromSpace
中拷贝temp2
到ToSpace
中时,发现引用了temp1
,便把temp1
也拷贝到ToSpace
,是一个递归的过程。但是在拷贝temp3
时发现也引用了temp1
,此时再把temp1
拷贝过去则重复了。
要避免重复拷贝,做法是拷贝时给对象添加一个标记visited
表示该节点已被访问过,后续通过visited
属性判断是否拷贝对象。
- 拷贝后保持正确的引用关系
还是上述引用关系,由于temp1
不需要重复拷贝,temp3
被拷贝到ToSpace
之后不知道temp1
对象在ToSpace
中的内存地址。
做法是temp1
被拷贝过去后该对象节点上会生成新的field
属性指向新的内存空间地址,同时更新到旧内存对象的forwarding
属性上,因此temp3
就可以通过旧temp1
的forwarding
属性找到在ToSpace
中的引用地址了。
内存对象同时存在于新生代和老生代之后,也带来了问题:
- 内存对象跨代(跨空间)后如何标记
const temp1 = {} const temp2 = { ref: temp1, }
比如上述代码中的两个对象temp1
和temp2
都存在于新生代,其中temp2
引用了temp1
。假设在经过GC
之后temp2
晋升到了老生代,那么在下次GC
的标记阶段,如何判断temp1
是否是存活对象呢?
在基于可达性分析算法中要知道temp1
是否存活,就必须要知道是否有根对象引用
引用了temp1
对象。如此的话,年轻代的GC
就要遍历所有的老生代对象判断是否有根引用对象引用了temp1
对象,如此的话分代算法就没有意义了。
解决版本就是维护一个记录所有的跨代引用的记录集,它是写缓冲区
的一个列表。只要有老生代中的内存对象指向了新生代内存对象时,就将老生代中该对象的内存引用记录到记录集中。由于这种情况一般发生在对象写的操作,顾称此为写屏障,还一种可能的情况就是发生在晋升时。记录集的维护只要关心对象的写操作和晋升操作即可。此是又带来了另一个问题:
- 每次写操作时维护记录集的额外开销
优化的手段是在一些Crankshaft
操作中是不需要写屏障的,还有就是栈上内存对象的写操作是不需要写屏障的。还有一些,更多的手段就不在这里过多讨论。
- 缓解
Scavenge
算法内存利用率不高问题
新生代内存中存活对象占比是相对较小的,因此可以在分配空间时,ToSpace
可以分配的小一些。做法是将ToSpace
空间分成S0
和S1
两部分,S0
用作于ToSpace
,S1
与原FromSpace
合并当成FromSpace
。
Scavenge算法中深度/广度优先的区别
垃圾回收算法中,识别内存对象是否是垃圾的机制一般有两种:引用计数和基于可达性分析。
到達可能性分析に基づいて、すべての ルート参照 (グローバル変数など) を検索し、すべてのルート参照、再帰的ルート参照上のすべての参照を走査します。走査されるものはすべて ライブ オブジェクト を指定してマークします。この時点では、空間内の他のメモリ オブジェクトは デッド オブジェクトであるため、有向グラフが構築されます。
再帰の制限を考慮して、再帰ロジックは通常、非再帰実装を採用します。一般的なものには、幅優先アルゴリズムと深さ優先アルゴリズムが含まれます。 2 つの違いは次のとおりです。
- は、深さ優先で
ToSpace
にコピーするときにメモリ オブジェクトの順序を変更し、参照関係を持つオブジェクトを近づけます。その理由は、自身をコピーした後、自身が参照するオブジェクトが直接コピーされるため、関連するオブジェクトがToSpace
- で近くにあるためです。深さの優先順位はちょうど逆です。
CPU のキャッシュ戦略により、メモリ オブジェクトを読み取るとき、より速くキャッシュにアクセスするために、その背後にあるオブジェクトが一緒に読み取られる可能性が高くなります。コード開発中の非常に一般的なシナリオは obj1.obj2.obj3
であるため、このとき、CPU が obj1
を読み取ると、次の obj2
であれば、 obj3
も一緒に読み込むとキャッシュにヒットするので非常に助かります。
したがって、深さ優先アルゴリズムは、ビジネス ロジックがキャッシュにヒットするのに役立ちますが、その実装には、メモリ領域を消費する追加のスタック支援アルゴリズムの実装が必要です。逆に、幅優先ではキャッシュ ヒットを改善することはできませんが、その実装ではポインタを使用してスペースの消費を巧みに回避でき、アルゴリズムの実行効率が高くなります。
新世代のメモリ オブジェクトの昇格条件
新世代のメモリ オブジェクトを旧世代に昇格させる場合は、次の条件を満たす必要があります。
- オブジェクトが経験済みかどうか
Scavenge
Recycling -
ToSpace
メモリ使用率が制限を超えることはできません
Scavenge の GC のロジックは、
GC のたびに生き残ったオブジェクトの age
属性を与えることです 1
、そして
GC## が再度実行されたとき # のときの age
属性を判断するだけです。基本的なプロモーション図は次のとおりです。
旧世代のメモリには長期にわたって存続するオブジェクトが多数あり、
アルゴリズムが使用される理由リサイクルできないのは次のとおりです:
- メモリ領域の半分が無駄になります
旧世代メモリ領域のガベージ コレクションは、
Mark-スイープ(Mark-スイープ
) および Mark-スイープ## を使用します。 #(
Mark -Compact) の組み合わせ方法。マーキングとクリアは 2 つの部分に分かれています。
#マーキング フェーズ
- #クリア フェーズ (マーキングとソートの場合は、ソート フェーズ)
- マーキング フェーズで古い学生を追跡する ヒープ メモリ内のすべてのメモリ オブジェクトが生成され、ライブ オブジェクトがマークされます。クリーンアップ フェーズでは、マークされていないオブジェクトのみがクリーンアップされます。その理由は、非生存オブジェクトが旧世代のメモリ内で占める割合が少数であるためです。
上図に示すように、マークのクリアの問題点の 1 つは、クリア後に使用できなくなる不連続な領域が存在するため、旧世代のメモリ クリーンアップが必要になることです。メモリ容量が必要なため、タグ付けと組み合わせたソリューション。この解決策は、マーキング プロセス中に生物オブジェクトを片側に移動し、移動の完了後に境界の外側にあるすべての非生物オブジェクトをクリーンアップして削除することです。
#ガベージ コレクションの完全な一時停止
ガベージ コレクション中にアプリケーションの実行ロジックを一時停止し、その後アプリケーションを再開する必要があります。ガベージ コレクション メカニズムの実行ロジックが完了した後、この動作は「完全一時停止 」と呼ばれ、通常は
Stop The World と呼ばれ、STW と呼ばれます。若い世代のメモリのガベージ コレクションはアプリケーションの実行にほとんど影響を与えませんが、旧世代のメモリには多くのオブジェクトが生き残っているため、旧世代のメモリのガベージ コレクションによって引き起こされる完全な一時停止の影響は非常に大きくなります。
incremental mark、
、 も導入しています。並行マーク
、増分クリーニング
、並行クリーニング
、遅延クリーニング
などの方法。 STW 最適化
ガベージ コレクションに費やされた時間を測定するための重要な指標は、GC の実行中にメインスレッドが一時停止されている時間です。 。 STW の影響は許容できないため、V8 では多くの最適化手法も採用されています。
- 並列 GC
GC プロセスは多くのことを実行する必要があり、メイン スレッドで STW 現象が発生します。並列 GC の方法は、複数の補助スレッドを開くことです。 GC 作業を共有するスレッド。このアプローチでも STW 現象を回避することはできませんが、有効な補助スレッドの数に応じて STW の合計時間を短縮できます。
- #インクリメンタル
- GC
- 同時実行
- GC
- GC
でのアニメーションのレンダリングはおよそです。 ##60 フレーム (各フレームは約
16ms)、現在のレンダリング時間が
16.6ms に達すると、次のような他のことを行うための自由時間が生まれます。パート番号 ##GC
タスク。
メモリをキャッシュとして使用するときは注意し、オブジェクトをキャッシュとして使用する場合にも注意してください。有効期限と無限の増大の問題を合理的に制限するには、lru 戦略を使用できます
- ユーザー セッションを
Node
に保存するためにメモリを使用しないでください。そうしないと、大量のユーザー セッション オブジェクトをメモリに保存すると、古い世代のメモリが急増します。 、クリーンアップのパフォーマンスに影響を及ぼし、アプリケーションの実行パフォーマンスとメモリ オーバーフローに影響を与えます。 Redis の使用方法の改善など。キャッシュを外部に移動する利点: - #常駐メモリ オブジェクトの数を減らし、ガベージ コレクションをより効率的にする
キャッシュをプロセス間で共有できる
- ノード関連の知識については、
- nodejs チュートリアル を参照してください。
以上がV8 のメモリ管理とガベージ コレクション アルゴリズムについて話しましょうの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









nvm でノードを削除する方法: 1. 「nvm-setup.zip」をダウンロードして C ドライブにインストールします; 2. 「nvm -v」コマンドで環境変数を構成し、バージョン番号を確認します; 3. 「nvm」を使用しますinstall" コマンド ノードのインストール; 4. "nvm uninstall" コマンドでインストールしたノードを削除します。

ファイルのアップロードをどのように処理するか?次の記事では、Express を使用してノード プロジェクトでファイルのアップロードを処理する方法を紹介します。

この期間中、私は Tencent ドキュメントのすべてのカテゴリに共通する HTML 動的サービスを開発していましたが、さまざまなカテゴリへのアクセスの生成と展開を容易にし、クラウド移行のトレンドに従うために、Docker を使用して修正することを検討しました。サービス内容や製品バージョンを一元管理します。この記事では、私が Docker を提供するプロセスで蓄積した最適化の経験を参考として共有します。

この記事では、Node のプロセス管理ツール「pm2」について説明し、pm2 が必要な理由、pm2 のインストール方法と使用方法について説明します。皆様のお役に立てれば幸いです。

ピン張りのノードの詳細な説明とインストールガイドこの記事では、ピネットワークのエコシステムを詳細に紹介します - PIノードは、ピン系生態系における重要な役割であり、設置と構成の完全な手順を提供します。 Pinetworkブロックチェーンテストネットワークの発売後、PIノードは多くの先駆者の重要な部分になり、テストに積極的に参加し、今後のメインネットワークリリースの準備をしています。まだピン張りのものがわからない場合は、ピコインとは何かを参照してください。リストの価格はいくらですか? PIの使用、マイニング、セキュリティ分析。パインワークとは何ですか?ピン競技プロジェクトは2019年に開始され、独占的な暗号通貨PIコインを所有しています。このプロジェクトは、誰もが参加できるものを作成することを目指しています

Nodejs実行可能ファイルをpkgでパッケージ化するにはどうすればよいですか?次の記事では、pkg を使用して Node プロジェクトを実行可能ファイルにパッケージ化する方法を紹介します。

「node-gyp.js」が「Node.js」のバージョンと一致しないため、npm node gyp が失敗します。解決策は次のとおりです: 1. 「npm cache clean -f」を使用してノード キャッシュをクリアします; 2. 「npm install -」を使用します。 g n" n モジュールをインストールします。 3. 「n v12.21.0」コマンドを使用して、「node v12.21.0」バージョンをインストールします。

シングルサインオンシステムとは何ですか? Nodejsを使用して実装するにはどうすればよいですか?次の記事ではnodeを使ってシングルサインオンシステムを実現する方法を紹介しますので、参考になれば幸いです。
