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.ScriptcachedData バッファがこの 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 キラーによってプロセスが終了するリスクがあります。

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

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 は 0/1 のブール値で、--zap_code_spaceオプションが有効になっているかどうかを示します。これにより、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() コンソール 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)

追加: v1.0.0

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

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

使用方法:

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

v8.stopCoverage()

追加: v15.1.0, v14.18.0, v12.22.0

v8.stopCoverage()メソッドを使用すると、NODE_V8_COVERAGEで開始されたカバレッジの収集を停止し、V8 が実行回数レコードを解放してコードを最適化できるようにすることができます。これは、オンデマンドでカバレッジを収集する場合にv8.takeCoverage()と組み合わせて使用できます。

v8.takeCoverage()

追加: v15.1.0, v14.18.0, v12.22.0

v8.takeCoverage()メソッドを使用すると、NODE_V8_COVERAGEで開始されたカバレッジをオンデマンドでディスクに書き込むことができます。このメソッドは、プロセスの存続期間中に複数回呼び出すことができます。実行カウンタは毎回リセットされ、新しいカバレッジレポートがNODE_V8_COVERAGEで指定されたディレクトリに書き込まれます。

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

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

[履歴]

バージョン変更
v19.1.0ヒープスナップショットの設定オプションをサポート
v18.0.0ファイルを書き込めなかった場合、例外がスローされるようになりました。
v18.0.0すべてのプラットフォームで返されるエラーコードを統一しました。
v11.13.0追加: 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 isolate に固有です。ワーカースレッドを使用する場合、メインスレッドから生成されたヒープスナップショットには、ワーカーに関する情報が含まれません。逆も同様です。

ヒープスナップショットを作成するには、スナップショットを作成する時点でのヒープの約 2 倍のメモリが必要です。これにより、OOM キラーがプロセスを終了するリスクがあります。

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

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}`)
    // メインスレッドのヒープダンプを取得します。
    console.log(`main thread heapdump: ${writeHeapSnapshot()}`)
  })

  // ワーカーにヒープダンプの作成を指示します。
  worker.postMessage('heapdump')
} else {
  parentPort.once('message', message => {
    if (message === 'heapdump') {
      // ワーカーのヒープダンプを生成し、ファイル名を親に返します。
      parentPort.postMessage(writeHeapSnapshot())
    }
  })
}

v8.setHeapSnapshotNearHeapLimit(limit)

追加: v18.10.0, v16.18.0

[安定版: 1 - 実験的]

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

コマンドラインから--heapsnapshot-near-heap-limitが既に設定されている場合、または API が複数回呼び出された場合は、この API は no-op です。limitは正の整数である必要があります。詳細は--heapsnapshot-near-heap-limitを参照してください。

シリアライゼーション API

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

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

v8.serialize(value)

追加: v8.0.0

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

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

v8.deserialize(buffer)

追加: 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)

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

serializer.writeDouble(value)

カスタムserializer._writeHostObject()内での使用を目的とした、JS number値の書き込み。

serializer.writeRawBytes(buffer)

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

serializer._writeHostObject(object)

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

このメソッドはSerializerクラス自体には存在せず、サブクラスで提供できます。

serializer._getDataCloneError(message)

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

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

serializer._getSharedArrayBufferId(sharedArrayBuffer)

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

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

このメソッドはSerializerクラス自体には存在せず、サブクラスで提供できます。

serializer._setTreatArrayBufferViewsAsHostObjects(flag)

TypedArrayおよびDataViewオブジェクトをホストオブジェクトとして扱うかどうかを示します。つまり、serializer._writeHostObject()に渡すかどうかを示します。

クラス: v8.Deserializer

追加されたバージョン: 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

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

クラス: v8.DefaultDeserializer

追加されたバージョン: v8.0.0

DefaultSerializer によって書き込まれた形式に対応する Deserializer のサブクラスです。

Promise フック

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

javascript
import { promiseHooks } from 'node:v8'

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

// `init` イベントは、Promise の作成を表します。これは、`new Promise(...)` などの直接的な作成、または `then()` や `catch()` などの継続である可能性があります。非同期関数が呼び出されたり、`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フックはプレーンな関数でなければなりません。非同期関数を指定すると、無限のマイクロタスクループが発生するため、エラーがスローされます。

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フックはプレーンな関数でなければなりません。非同期関数を指定すると、無限のマイクロタスクループが発生するため、エラーがスローされます。

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フックはプレーンな関数でなければなりません。非同期関数を指定すると、無限のマイクロタスクループが発生するため、エラーがスローされます。

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)

追加されたバージョン: v17.1.0, v16.14.0

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

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)

追加されたバージョン: v17.1.0, v16.14.0

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

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

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) {},
})

フックコールバック

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

これらのフックはasync_hooksのものと似ていますが、destroyフックがありません。他の種類の非同期リソースは、通常、ソケットまたはファイル記述子を表現し、destroyライフサイクルイベントを表す明確な「閉じた」状態を持ちますが、Promise はコードがまだアクセスできる限り使用可能です。ガベージコレクションの追跡を使用して、Promise をasync_hooksイベントモデルに適合させますが、この追跡は非常に高価であり、必ずしもガベージコレクションされるわけではありません。

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

この API は Promise イベントをasync_hooksに供給するために使用されますが、両者の間の順序は定義されていません。両方の 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)

then()catch()finally()ハンドラの後、または別のawaitの後のawaitの前に、Promise の継続実行の直後に呼び出されます。

settled(promise)

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

スタートアップスナップショット 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()

  // ディレクトリから一連のファイルを読み込み、storageに格納します。
  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.envprocess.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 アプリケーションのエントリポイントを設定します。これは、スナップショット構築スクリプトで一度だけ呼び出すことができます。呼び出された場合、デシリアライズされたアプリケーションは起動するための追加のエントリポイントスクリプトを必要としなくなり、デシリアライズされたデータ(指定されている場合)と共にコールバックを呼び出すだけです。そうでない場合、デシリアライズされたアプリケーションにはエントリポイントスクリプトを依然として提供する必要があります。

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)