Skip to content

V8

ソースコード: lib/v8.js

node:v8モジュールは、Node.jsバイナリに組み込まれているV8のバージョンに固有のAPIを公開します。これは、以下を使用してアクセスできます。

js
const v8 = require('node:v8');

v8.cachedDataVersionTag()

追加: v8.0.0

V8のバージョン、コマンドラインフラグ、および検出されたCPU機能から派生したバージョンタグを表す整数を返します。これは、vm.Script cachedDataバッファがこのV8のインスタンスと互換性があるかどうかを判断するのに役立ちます。

js
console.log(v8.cachedDataVersionTag()); // 3947234607
// v8.cachedDataVersionTag()によって返される値は、V8の
// バージョン、コマンドラインフラグ、および検出されたCPU機能から派生します。
// フラグが切り替えられたときに、値が実際に更新されることをテストします。
v8.setFlagsFromString('--allow_natives_syntax');
console.log(v8.cachedDataVersionTag()); // 183726201

v8.getHeapCodeStatistics()

追加: v12.8.0

ヒープ内のコードとそのメタデータに関する統計情報を取得します。V8 GetHeapCodeAndMetadataStatistics APIを参照してください。次のプロパティを持つオブジェクトを返します。

js
{
  code_and_metadata_size: 212208,
  bytecode_and_metadata_size: 161368,
  external_script_source_size: 1410794,
  cpu_profiler_metadata_size: 0,
}

v8.getHeapSnapshot([options])

[履歴]

バージョン変更
v19.1.0ヒープスナップショットを設定するオプションをサポートします。
v11.13.0追加: v11.13.0
  • options <Object>

    • exposeInternals <boolean> true の場合、ヒープスナップショットで内部を公開します。デフォルト: false
    • exposeNumericValues <boolean> true の場合、人工的なフィールドで数値型を公開します。デフォルト: false
  • 戻り値: <stream.Readable> V8 ヒープスナップショットを含む Readable。

現在の V8 ヒープのスナップショットを生成し、JSON シリアライズされた表現を読み取るために使用できる Readable Stream を返します。 この JSON ストリーム形式は、Chrome DevTools などのツールで使用することを目的としています。 JSON スキーマは文書化されておらず、V8 エンジンに固有のものです。 したがって、スキーマは V8 のバージョンによって変更される可能性があります。

ヒープスナップショットの作成には、スナップショットの作成時にヒープの約 2 倍のサイズのメモリが必要です。 これにより、OOM killer がプロセスを終了させるリスクが生じます。

スナップショットの生成は同期操作であり、ヒープサイズに応じてイベントループを一定時間ブロックします。

js
// ヒープスナップショットをコンソールに出力
const v8 = require('node:v8');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout);

v8.getHeapSpaceStatistics()

[履歴]

バージョン変更
v7.5.032 ビット符号なし整数範囲を超える値をサポートします。
v6.0.0追加: v6.0.0

V8 ヒープスペース、つまり V8 ヒープを構成するセグメントに関する統計を返します。 ヒープスペースの順序も、ヒープスペースの可用性も保証できません。統計は V8 の GetHeapSpaceStatistics 関数を介して提供され、V8 のバージョンによって変更される可能性があるためです。

返される値は、次のプロパティを含むオブジェクトの配列です。

json
[
  {
    "space_name": "new_space",
    "space_size": 2063872,
    "space_used_size": 951112,
    "space_available_size": 80824,
    "physical_space_size": 2063872
  },
  {
    "space_name": "old_space",
    "space_size": 3090560,
    "space_used_size": 2493792,
    "space_available_size": 0,
    "physical_space_size": 3090560
  },
  {
    "space_name": "code_space",
    "space_size": 1260160,
    "space_used_size": 644256,
    "space_available_size": 960,
    "physical_space_size": 1260160
  },
  {
    "space_name": "map_space",
    "space_size": 1094160,
    "space_used_size": 201608,
    "space_available_size": 0,
    "physical_space_size": 1094160
  },
  {
    "space_name": "large_object_space",
    "space_size": 0,
    "space_used_size": 0,
    "space_available_size": 1490980608,
    "physical_space_size": 0
  }
]

v8.getHeapStatistics()

[履歴]

バージョン変更点
v7.5.032ビット符号なし整数の範囲を超える値をサポートしました。
v7.2.0malloced_memory, peak_malloced_memory, および does_zap_garbage を追加しました。
v1.0.0追加: v1.0.0

次のプロパティを持つオブジェクトを返します。

total_heap_size total_heap_size の値は、V8 がヒープに割り当てたバイト数です。 used_heap がより多くのメモリを必要とする場合、これは増加する可能性があります。

total_heap_size_executable total_heap_size_executable の値は、実行可能コードを含むことができるヒープの部分のバイト数です。 これには、JITコンパイルされたコードによって使用されるメモリと、実行可能状態に保つ必要のあるメモリが含まれます。

total_physical_size total_physical_size の値は、V8 ヒープによって使用される実際の物理メモリのバイト数です。 これは、予約されているのではなく、コミットされている(または使用されている)メモリの量です。

total_available_size total_available_size の値は、V8 ヒープで使用できるメモリのバイト数です。 この値は、V8 がヒープ制限を超える前に使用できるメモリの量を表します。

used_heap_size used_heap_size の値は、現在 V8 の JavaScript オブジェクトによって使用されているバイト数です。 これは実際に使用されているメモリであり、割り当てられているがまだ使用されていないメモリは含まれません。

heap_size_limit heap_size_limit の値は、V8 ヒープの最大サイズ(バイト単位)です(システムの制約によって決定されるデフォルトの制限、または --max_old_space_size オプションに渡される値)。

malloced_memory malloced_memory の値は、V8 によって malloc を介して割り当てられたバイト数です。

peak_malloced_memory peak_malloced_memory の値は、プロセスの存続期間中に V8 によって malloc を介して割り当てられたバイト数のピークです。

does_zap_garbage は、--zap_code_space オプションが有効になっているかどうかを示す 0/1 のブール値です。 これにより、V8 はヒープガベージをビットパターンで上書きします。 RSSフットプリント(レジデントセットサイズ)は、すべてのヒープページに継続的に触れるため、大きくなり、オペレーティングシステムによってスワップアウトされる可能性が低くなります。

number_of_native_contexts native_context の値は、現在アクティブなトップレベルのコンテキストの数です。 この数値が時間の経過とともに増加すると、メモリリークを示します。

number_of_detached_contexts detached_context の値は、切り離されたが、まだガベージコレクションされていないコンテキストの数です。 この数値がゼロ以外の場合、メモリリークの可能性があります。

total_global_handles_size total_global_handles_size の値は、V8 グローバルハンドルの合計メモリサイズです。

used_global_handles_size used_global_handles_size の値は、V8 グローバルハンドルの使用済みメモリサイズです。

external_memory external_memory の値は、配列バッファと外部文字列のメモリサイズです。

js
{
  total_heap_size: 7326976,
  total_heap_size_executable: 4194304,
  total_physical_size: 7326976,
  total_available_size: 1152656,
  used_heap_size: 3476208,
  heap_size_limit: 1535115264,
  malloced_memory: 16384,
  peak_malloced_memory: 1127496,
  does_zap_garbage: 0,
  number_of_native_contexts: 1,
  number_of_detached_contexts: 0,
  total_global_handles_size: 8192,
  used_global_handles_size: 3296,
  external_memory: 318824
}

v8.queryObjects(ctor[, options])

追加: v22.0.0, v20.13.0

[安定版: 1 - 実験的]

安定版: 1 安定版: 1.1 - 開発中

  • ctor <Function> ヒープ内の対象オブジェクトをフィルタリングするためにプロトタイプチェーン上で検索するために使用できるコンストラクタ。

  • options <undefined> | <Object>

    • format <string> 'count' の場合、一致したオブジェクトの数が返されます。 'summary' の場合、一致したオブジェクトの概要文字列の配列が返されます。
  • 戻り値: {number|Array

これは、Chromium DevToolsコンソールによって提供される queryObjects() console API と似ています。 メモリリーク回帰テストに役立つ可能性がある、完全なガベージコレクション後にヒープ内のプロトタイプチェーンに一致するコンストラクタを持つオブジェクトを検索するために使用できます。 予期しない結果を避けるために、ユーザーは実装を制御できないコンストラクタ、またはアプリケーション内の他のパーティによって呼び出すことができるコンストラクタでこのAPIを使用することを避ける必要があります。

偶発的なリークを避けるために、このAPIは見つかったオブジェクトへの生の参照を返しません。 デフォルトでは、見つかったオブジェクトの数を返します。 options.format'summary' の場合、各オブジェクトの簡単な文字列表現を含む配列を返します。 このAPIで提供される可視性はヒープスナップショットが提供するものと似ていますが、ユーザーはシリアル化と解析のコストを節約し、検索中にターゲットオブジェクトを直接フィルタリングできます。

現在の実行コンテキストで作成されたオブジェクトのみが結果に含まれます。

js
const { queryObjects } = require('node:v8');
class A { foo = 'bar'; }
console.log(queryObjects(A)); // 0
const a = new A();
console.log(queryObjects(A)); // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));

class B extends A { bar = 'qux'; }
const b = new B();
console.log(queryObjects(B)); // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }));

// Note that, when there are child classes inheriting from a constructor,
// the constructor also shows up in the prototype chain of the child
// classes's prototype, so the child classes's prototype would also be
// included in the result.
console.log(queryObjects(A));  // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));
js
import { queryObjects } from 'node:v8';
class A { foo = 'bar'; }
console.log(queryObjects(A)); // 0
const a = new A();
console.log(queryObjects(A)); // 1
// [ "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));

class B extends A { bar = 'qux'; }
const b = new B();
console.log(queryObjects(B)); // 1
// [ "B { foo: 'bar', bar: 'qux' }" ]
console.log(queryObjects(B, { format: 'summary' }));

// Note that, when there are child classes inheriting from a constructor,
// the constructor also shows up in the prototype chain of the child
// classes's prototype, so the child classes's prototype would also be
// included in the result.
console.log(queryObjects(A));  // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }));

v8.setFlagsFromString(flags)

Added in: v1.0.0

v8.setFlagsFromString() メソッドは、V8 のコマンドラインフラグをプログラムで設定するために使用できます。このメソッドは注意して使用する必要があります。VM の起動後に設定を変更すると、クラッシュやデータ損失を含む予測不可能な動作が発生したり、何も起こらなかったりする可能性があります。

Node.js のバージョンで使用できる V8 のオプションは、node --v8-options を実行することで確認できます。

使用例:

js
// GC イベントを 1 分間標準出力に出力します。
const v8 = require('node:v8');
v8.setFlagsFromString('--trace_gc');
setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3);

v8.stopCoverage()

Added in: v15.1.0, v14.18.0, v12.22.0

v8.stopCoverage() メソッドを使用すると、NODE_V8_COVERAGE によって開始されたカバレッジ収集を停止し、V8 が実行カウントレコードを解放してコードを最適化できるようにすることができます。これは、ユーザーが必要に応じてカバレッジを収集したい場合に、v8.takeCoverage() と組み合わせて使用できます。

v8.takeCoverage()

Added in: v15.1.0, v14.18.0, v12.22.0

v8.takeCoverage() メソッドを使用すると、ユーザーは NODE_V8_COVERAGE によって開始されたカバレッジを、必要に応じてディスクに書き込むことができます。このメソッドは、プロセスのライフサイクル中に複数回呼び出すことができます。毎回、実行カウンターがリセットされ、NODE_V8_COVERAGE で指定されたディレクトリに新しいカバレッジレポートが書き込まれます。

プロセスが終了しようとするとき、プロセスが終了する前に v8.stopCoverage() が呼び出されない限り、最後のカバレッジがディスクに書き込まれます。

v8.writeHeapSnapshot([filename[,options]])

[History]

VersionChanges
v19.1.0Support options to configure the heap snapshot.
v18.0.0An exception will now be thrown if the file could not be written.
v18.0.0Make the returned error codes consistent across all platforms.
v11.13.0Added in: v11.13.0
  • filename <string> V8 のヒープスナップショットを保存するファイルパス。指定しない場合、'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot' というパターンでファイル名が生成されます。ここで、{pid} は Node.js プロセスの PID、{thread_id}writeHeapSnapshot() がメインの Node.js スレッドから呼び出された場合は 0、ワーカースレッドの ID になります。

  • options <Object>

    • exposeInternals <boolean> true の場合、ヒープスナップショットで内部を公開します。デフォルト: false
    • exposeNumericValues <boolean> true の場合、人工的なフィールドに数値型の値を公開します。デフォルト: false
  • 戻り値: <string> スナップショットが保存されたファイル名。

現在の V8 ヒープのスナップショットを生成し、JSON ファイルに書き込みます。このファイルは、Chrome DevTools などのツールで使用することを目的としています。JSON スキーマはドキュメント化されておらず、V8 エンジンに固有であり、V8 のバージョンによって異なる場合があります。

ヒープスナップショットは、単一の V8 分離に固有です。ワーカーースレッド を使用する場合、メインスレッドから生成されたヒープスナップショットには、ワーカーに関する情報は含まれず、その逆も同様です。

ヒープスナップショットを作成するには、スナップショットが作成された時点のヒープサイズの約 2 倍のメモリが必要です。これにより、OOM killer がプロセスを終了させるリスクが生じます。

スナップショットの生成は、ヒープサイズに応じてイベントループをブロックする同期操作です。

js
const { writeHeapSnapshot } = require('node:v8');
const {
  Worker,
  isMainThread,
  parentPort,
} = require('node:worker_threads');

if (isMainThread) {
  const worker = new Worker(__filename);

  worker.once('message', (filename) => {
    console.log(`worker heapdump: ${filename}`);
    // Now get a heapdump for the main thread.
    console.log(`main thread heapdump: ${writeHeapSnapshot()}`);
  });

  // Tell the worker to create a heapdump.
  worker.postMessage('heapdump');
} else {
  parentPort.once('message', (message) => {
    if (message === 'heapdump') {
      // Generate a heapdump for the worker
      // and return the filename to the parent.
      parentPort.postMessage(writeHeapSnapshot());
    }
  });
}

v8.setHeapSnapshotNearHeapLimit(limit)

Added in: v18.10.0, v16.18.0

[Stable: 1 - Experimental]

Stable: 1 安定版: 1 - 試験的

この API は、--heapsnapshot-near-heap-limit がコマンドラインからすでに設定されている場合、または API が複数回呼び出された場合は何もしません。 limit は正の整数でなければなりません。 詳細については、--heapsnapshot-near-heap-limit を参照してください。

シリアライゼーション API

シリアライゼーション API は、HTML 構造化クローンアルゴリズム と互換性のある方法で JavaScript の値をシリアライズする手段を提供します。

この形式は後方互換性があります(つまり、ディスクに保存しても安全です)。 等しい JavaScript の値は、異なるシリアライズされた出力になる可能性があります。

v8.serialize(value)

Added in: v8.0.0

DefaultSerializer を使用して、value をバッファーにシリアライズします。

ERR_BUFFER_TOO_LARGE は、buffer.constants.MAX_LENGTH より大きいバッファーを必要とする巨大なオブジェクトをシリアライズしようとするとスローされます。

v8.deserialize(buffer)

Added in: v8.0.0

デフォルトのオプションで DefaultDeserializer を使用して、バッファーから JS 値を読み取ります。

クラス: v8.Serializer

追加: v8.0.0

new Serializer()

新しい Serializer オブジェクトを作成します。

serializer.writeHeader()

シリアライゼーション形式のバージョンを含むヘッダーを書き出します。

serializer.writeValue(value)

JavaScript の値をシリアライズし、シリアライズされた表現を内部バッファに追加します。

value がシリアライズできない場合、これはエラーをスローします。

serializer.releaseBuffer()

格納されている内部バッファを返します。このシリアライザーは、バッファが解放されると使用すべきではありません。このメソッドを呼び出すと、以前の書き込みが失敗した場合、未定義の動作が発生します。

serializer.transferArrayBuffer(id, arrayBuffer)

ArrayBuffer のコンテンツが帯域外に転送されたことを示します。デシリアライズのコンテキストで対応する ArrayBufferdeserializer.transferArrayBuffer() に渡します。

serializer.writeUint32(value)

生の 32 ビット符号なし整数を書き込みます。カスタム serializer._writeHostObject() の内部で使用します。

serializer.writeUint64(hi, lo)

生の 64 ビット符号なし整数を、上位と下位の 32 ビット部分に分割して書き込みます。カスタム serializer._writeHostObject() の内部で使用します。

serializer.writeDouble(value)

JSのnumber値を書き込みます。カスタムのserializer._writeHostObject()の中で使用します。

serializer.writeRawBytes(buffer)

生のバイトをシリアライザーの内部バッファーに書き込みます。デシリアライザーは、バッファーの長さを計算する方法を必要とします。カスタムのserializer._writeHostObject()の中で使用します。

serializer._writeHostObject(object)

このメソッドは、何らかの種類のホストオブジェクト、つまりネイティブC++バインディングによって作成されたオブジェクトを書き込むために呼び出されます。objectをシリアライズできない場合は、適切な例外をスローする必要があります。

このメソッドは、Serializerクラス自体には存在しませんが、サブクラスによって提供できます。

serializer._getDataCloneError(message)

このメソッドは、オブジェクトをクローンできない場合にスローされるエラーオブジェクトを生成するために呼び出されます。

このメソッドはデフォルトでErrorコンストラクターを使用し、サブクラスでオーバーライドできます。

serializer._getSharedArrayBufferId(sharedArrayBuffer)

このメソッドは、シリアライザーがSharedArrayBufferオブジェクトをシリアライズしようとするときに呼び出されます。オブジェクトに対して符号なし32ビットの整数IDを返す必要があります。このSharedArrayBufferがすでにシリアライズされている場合は、同じIDを使用します。デシリアライズする場合、このIDはdeserializer.transferArrayBuffer()に渡されます。

オブジェクトをシリアライズできない場合は、例外をスローする必要があります。

このメソッドは、Serializerクラス自体には存在しませんが、サブクラスによって提供できます。

serializer._setTreatArrayBufferViewsAsHostObjects(flag)

TypedArrayDataViewオブジェクトをホストオブジェクトとして扱うかどうかを示します。つまり、それらをserializer._writeHostObject()に渡します。

Class: v8.Deserializer

Added in: v8.0.0

new Deserializer(buffer)

新しいDeserializerオブジェクトを作成します。

deserializer.readHeader()

ヘッダー(フォーマットバージョンを含む)を読み取り検証します。 例えば、無効またはサポートされていないワイヤフォーマットを拒否する場合があります。 その場合、Errorがスローされます。

deserializer.readValue()

JavaScriptの値をバッファからデシリアライズして返します。

deserializer.transferArrayBuffer(id, arrayBuffer)

ArrayBufferの内容が帯域外に転送されたことをマークします。 シリアライズコンテキストで対応するArrayBufferserializer.transferArrayBuffer()に渡します(またはSharedArrayBufferの場合はserializer._getSharedArrayBufferId()からidを返します)。

deserializer.getWireFormatVersion()

基となるワイヤフォーマットのバージョンを読み取ります。レガシーコードが古いワイヤフォーマットのバージョンを読み取る場合に主に役立ちます。.readHeader() の前に呼び出すことはできません。

deserializer.readUint32()

生の 32 ビット符号なし整数を読み取り、それを返します。カスタムの deserializer._readHostObject() の内部で使用します。

deserializer.readUint64()

生の 64 ビット符号なし整数を読み取り、それを 2 つの 32 ビット符号なし整数のエントリを持つ配列 [hi, lo] として返します。カスタムの deserializer._readHostObject() の内部で使用します。

deserializer.readDouble()

JS の number 値を読み取ります。カスタムの deserializer._readHostObject() の内部で使用します。

deserializer.readRawBytes(length)

デシリアライザーの内部バッファーから生のバイトを読み取ります。length パラメーターは、serializer.writeRawBytes() に渡されたバッファーの長さに対応している必要があります。カスタムの deserializer._readHostObject() の内部で使用します。

deserializer._readHostObject()

このメソッドは、何らかの種類のホストオブジェクト、つまりネイティブ C++ バインディングによって作成されたオブジェクトを読み取るために呼び出されます。データのデシリアライズが不可能な場合は、適切な例外をスローする必要があります。

このメソッドは Deserializer クラス自体には存在しませんが、サブクラスによって提供される場合があります。

クラス: v8.DefaultSerializer

追加: v8.0.0

TypedArray (特にBuffer) と DataView オブジェクトをホストオブジェクトとしてシリアライズし、それらが参照している基礎となる ArrayBuffer の一部のみを格納する Serializer のサブクラス。

クラス: v8.DefaultDeserializer

追加: v8.0.0

DefaultSerializer によって書き込まれたフォーマットに対応する Deserializer のサブクラス。

Promise hooks

promiseHooks インターフェースは、promise ライフサイクルイベントを追跡するために使用できます。すべての非同期アクティビティを追跡するには、内部でこのモジュールを使用して、他の非同期リソースのイベントに加えて promise ライフサイクルイベントを生成する async_hooks を参照してください。リクエストコンテキストの管理については、AsyncLocalStorage を参照してください。

js
import { promiseHooks } from 'node:v8';

// promise によって生成されるライフサイクルイベントは 4 つあります。

// `init` イベントは、promise の作成を表します。これは、`new Promise(...)`
// のような直接的な作成、または `then()` や `catch()` のような継続である可能性があります。
// また、async 関数が呼び出されるか、`await` が実行されるたびにも発生します。
// 継続 promise が作成される場合、`parent` はその継続元となる promise になります。
function init(promise, parent) {
  console.log('a promise was created', { promise, parent });
}

// `settled` イベントは、promise が解決または拒否の値を受け取ったときに発生します。
// これは、promise 以外の入力で `Promise.resolve()` を使用する場合など、
// 同期的に発生する可能性があります。
function settled(promise) {
  console.log('a promise resolved or rejected', { promise });
}

// `before` イベントは、`then()` または `catch()` ハンドラーが実行される直前、
// または `await` が実行を再開する直前に実行されます。
function before(promise) {
  console.log('a promise is about to call a then handler', { promise });
}

// `after` イベントは、`then()` ハンドラーが実行された直後、
// または別のハンドラーから再開した後に `await` が開始されるときに実行されます。
function after(promise) {
  console.log('a promise is done calling a then handler', { promise });
}

// ライフサイクルフックは、個別に開始および停止できます
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);

// または、グループで開始および停止することもできます
const stopHookSet = promiseHooks.createHook({
  init,
  settled,
  before,
  after,
});

// フックを停止するには、作成時に返された関数を呼び出します。
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet();

promiseHooks.onInit(init)

追加: v17.1.0, v16.14.0

init フックはプレーンな関数でなければなりません。async 関数を指定すると、無限マイクロタスク ループが発生するため、例外がスローされます。

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onInit((promise, parent) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onInit((promise, parent) => {});

promiseHooks.onSettled(settled)

追加: v17.1.0, v16.14.0

settled フックはプレーンな関数でなければなりません。async 関数を指定すると、無限マイクロタスク ループが発生するため、例外がスローされます。

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onSettled((promise) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onSettled((promise) => {});

promiseHooks.onBefore(before)

追加: v17.1.0, v16.14.0

before フックはプレーンな関数でなければなりません。async 関数を指定すると、無限マイクロタスク ループが発生するため、例外がスローされます。

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onBefore((promise) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onBefore((promise) => {});

promiseHooks.onAfter(after)

Added in: v17.1.0, v16.14.0

afterフックはプレーンな関数でなければなりません。async関数を提供すると、無限のマイクロタスクループが発生するため、スローされます。

js
import { promiseHooks } from 'node:v8';

const stop = promiseHooks.onAfter((promise) => {});
js
const { promiseHooks } = require('node:v8');

const stop = promiseHooks.onAfter((promise) => {});

promiseHooks.createHook(callbacks)

Added in: v17.1.0, v16.14.0

フックコールバックはプレーンな関数でなければなりません。async関数を提供すると、無限のマイクロタスクループが発生するため、スローされます。

各プロミスのさまざまなライフタイムイベントに対して呼び出される関数を登録します。

コールバックinit()/before()/after()/settled()は、プロミスのライフタイム中のそれぞれのイベントに対して呼び出されます。

すべてのコールバックはオプションです。たとえば、プロミスの作成のみを追跡する必要がある場合は、initコールバックのみを渡す必要があります。callbacksに渡すことができるすべての関数の詳細は、フックコールバックセクションにあります。

js
import { promiseHooks } from 'node:v8';

const stopAll = promiseHooks.createHook({
  init(promise, parent) {},
});
js
const { promiseHooks } = require('node:v8');

const stopAll = promiseHooks.createHook({
  init(promise, parent) {},
});

Hook callbacks

Promise のライフサイクルにおける主要なイベントは、promise の作成、継続ハンドラーが呼び出される前/後、または await の前後、そして promise が解決または拒否されるときに、4 つの領域に分類されます。

これらのフックは async_hooks のものと似ていますが、destroy フックがありません。他のタイプの非同期リソースは通常、ソケットまたはファイルディスクリプターを表し、destroy ライフサイクルイベントを表現するための明確な「クローズ」状態を持っていますが、promise はコードがまだ到達できる限り使用可能なままです。ガベージコレクションのトラッキングは、promise を async_hooks イベントモデルに適合させるために使用されますが、このトラッキングは非常にコストがかかり、ガベージコレクションされるとは限りません。

promise は promise フックメカニズムを介してライフサイクルが追跡される非同期リソースであるため、init()before()after()、および settled() コールバックは、無限ループを作成する可能性のあるより多くの promise を作成するため、非同期関数であってはなりません

この API は promise イベントを async_hooks に供給するために使用されますが、2 つの間の順序は定義されていません。どちらの API もマルチテナントであるため、互いに対して任意の順序でイベントを生成する可能性があります。

init(promise, parent)

  • promise <Promise> 作成中の promise。
  • parent <Promise> 該当する場合、継続元の promise。

promise が構築されるときに呼び出されます。 これは、対応する before/after イベントが発生することを意味するものではありません。継続を取得せずに promise が作成された場合にのみ発生します。

before(promise)

promise の継続が実行される前に呼び出されます。 これは、then()catch()、または finally() ハンドラーの形式、または再開する await の形式である可能性があります。

before コールバックは 0 から N 回呼び出されます。 promise の継続が作成されなかった場合、before コールバックは通常 0 回呼び出されます。 同じ promise から多くの継続が作成された場合、before コールバックは複数回呼び出される場合があります。

after(promise)

Promiseの継続が実行された直後に呼び出されます。これは、then()catch()、またはfinally()ハンドラーの後、または別のawaitの後のawaitの前に発生する可能性があります。

settled(promise)

Promiseが解決または拒否の値を受け取ったときに呼び出されます。これは、Promise.resolve()またはPromise.reject()の場合に同期的に発生する可能性があります。

Startup Snapshot API

追加: v18.6.0, v16.17.0

[安定版: 1 - 実験的]

安定版: 1 安定性: 1 - 実験的

v8.startupSnapshotインターフェースを使用して、カスタムスタートアップスナップショットのシリアライズおよびデシリアライズフックを追加できます。

bash
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# これはスナップショットを使用してプロセスを起動します {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob

上記の例では、entry.jsv8.startupSnapshotインターフェースのメソッドを使用して、シリアライズ中にカスタムオブジェクトの情報をスナップショットに保存する方法と、スナップショットのデシリアライズ中にこれらのオブジェクトを同期するために情報をどのように使用できるかを指定できます。たとえば、entry.jsに次のスクリプトが含まれている場合:

js
'use strict';

const fs = require('node:fs');
const zlib = require('node:zlib');
const path = require('node:path');
const assert = require('node:assert');

const v8 = require('node:v8');

class BookShelf {
  storage = new Map();

  // ディレクトリから一連のファイルを読み取り、ストレージに保存します。
  constructor(directory, books) {
    for (const book of books) {
      this.storage.set(book, fs.readFileSync(path.join(directory, book)));
    }
  }

  static compressAll(shelf) {
    for (const [ book, content ] of shelf.storage) {
      shelf.storage.set(book, zlib.gzipSync(content));
    }
  }

  static decompressAll(shelf) {
    for (const [ book, content ] of shelf.storage) {
      shelf.storage.set(book, zlib.gunzipSync(content));
    }
  }
}

// __dirname は、スナップショット構築時にスナップショットスクリプトが配置される場所です。
const shelf = new BookShelf(__dirname, [
  'book1.en_US.txt',
  'book1.es_ES.txt',
  'book2.zh_CN.txt',
]);

assert(v8.startupSnapshot.isBuildingSnapshot());
// スナップショットのシリアライズ時に、サイズを小さくするために書籍を圧縮します。
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
// スナップショットのデシリアライズ時に、書籍を解凍します。
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
  // process.env および process.argv はスナップショットの
  // デシリアライズ中にリフレッシュされます。
  const lang = process.env.BOOK_LANG || 'en_US';
  const book = process.argv[1];
  const name = `${book}.${lang}.txt`;
  console.log(shelf.storage.get(name));
}, shelf);

結果として得られるバイナリは、起動中にスナップショットからデシリアライズされたデータを出力し、起動されたプロセスのリフレッシュされた process.env および process.argv を使用します。

bash
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
# スナップショットからデシリアライズされた book1.es_ES.txt の内容を出力します。 {#prints-content-of-book1es_estxt-deserialized-from-the-snapshot}

現在、ユーザーランドスナップショットからデシリアライズされたアプリケーションを再度スナップショット化することはできません。そのため、これらのAPIは、ユーザーランドスナップショットからデシリアライズされていないアプリケーションでのみ利用できます。

v8.startupSnapshot.addSerializeCallback(callback[, data])

追加: v18.6.0, v16.17.0

  • callback <Function> シリアル化の前に呼び出されるコールバック。
  • data <any> コールバックが呼び出されるときに渡されるオプションのデータ。

Node.js インスタンスがスナップショットにシリアル化されようとし、終了しようとするときに呼び出されるコールバックを追加します。これは、シリアル化すべきでない、またはシリアル化できないリソースを解放したり、ユーザーデータをシリアル化に適した形式に変換したりするために使用できます。

コールバックは、追加された順に実行されます。

v8.startupSnapshot.addDeserializeCallback(callback[, data])

追加: v18.6.0, v16.17.0

  • callback <Function> スナップショットのデシリアル化後に呼び出されるコールバック。
  • data <any> コールバックが呼び出されるときに渡されるオプションのデータ。

Node.js インスタンスがスナップショットからデシリアル化されるときに呼び出されるコールバックを追加します。callbackdata (提供されている場合) はスナップショットにシリアル化され、アプリケーションの状態を再初期化したり、アプリケーションがスナップショットから再起動されたときにアプリケーションが必要とするリソースを再取得したりするために使用できます。

コールバックは、追加された順に実行されます。

v8.startupSnapshot.setDeserializeMainFunction(callback[, data])

追加: v18.6.0, v16.17.0

  • callback <Function> スナップショットのデシリアル化後にエントリポイントとして呼び出されるコールバック。
  • data <any> コールバックが呼び出されるときに渡されるオプションのデータ。

これは、Node.js アプリケーションがスナップショットからデシリアル化されるときのエントリポイントを設定します。これは、スナップショットビルドスクリプトで 1 回だけ呼び出すことができます。呼び出された場合、デシリアル化されたアプリケーションは起動するために追加のエントリポイントスクリプトを必要としなくなり、デシリアル化されたデータ (提供されている場合) とともにコールバックを単純に呼び出します。そうでない場合、エントリポイントスクリプトはデシリアル化されたアプリケーションに提供する必要があります。

v8.startupSnapshot.isBuildingSnapshot()

追加: v18.6.0, v16.17.0

Node.js インスタンスがスナップショットを作成するために実行されている場合は true を返します。

クラス: v8.GCProfiler

追加: v19.6.0, v18.15.0

この API は、現在のスレッドで GC データを収集します。

new v8.GCProfiler()

追加: v19.6.0, v18.15.0

v8.GCProfiler クラスの新しいインスタンスを作成します。

profiler.start()

追加: v19.6.0, v18.15.0

GC データの収集を開始します。

profiler.stop()

追加: v19.6.0, v18.15.0

GC データの収集を停止し、オブジェクトを返します。オブジェクトの内容は次のとおりです。

json
{
  "version": 1,
  "startTime": 1674059033862,
  "statistics": [
    {
      "gcType": "Scavenge",
      "beforeGC": {
        "heapStatistics": {
          "totalHeapSize": 5005312,
          "totalHeapSizeExecutable": 524288,
          "totalPhysicalSize": 5226496,
          "totalAvailableSize": 4341325216,
          "totalGlobalHandlesSize": 8192,
          "usedGlobalHandlesSize": 2112,
          "usedHeapSize": 4883840,
          "heapSizeLimit": 4345298944,
          "mallocedMemory": 254128,
          "externalMemory": 225138,
          "peakMallocedMemory": 181760
        },
        "heapSpaceStatistics": [
          {
            "spaceName": "read_only_space",
            "spaceSize": 0,
            "spaceUsedSize": 0,
            "spaceAvailableSize": 0,
            "physicalSpaceSize": 0
          }
        ]
      },
      "cost": 1574.14,
      "afterGC": {
        "heapStatistics": {
          "totalHeapSize": 6053888,
          "totalHeapSizeExecutable": 524288,
          "totalPhysicalSize": 5500928,
          "totalAvailableSize": 4341101384,
          "totalGlobalHandlesSize": 8192,
          "usedGlobalHandlesSize": 2112,
          "usedHeapSize": 4059096,
          "heapSizeLimit": 4345298944,
          "mallocedMemory": 254128,
          "externalMemory": 225138,
          "peakMallocedMemory": 181760
        },
        "heapSpaceStatistics": [
          {
            "spaceName": "read_only_space",
            "spaceSize": 0,
            "spaceUsedSize": 0,
            "spaceAvailableSize": 0,
            "physicalSpaceSize": 0
          }
        ]
      }
    }
  ],
  "endTime": 1674059036865
}

次に例を示します。

js
const { GCProfiler } = require('node:v8');
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
  console.log(profiler.stop());
}, 1000);