xref: /third_party/node/doc/api/v8.md (revision 1cb0ef41)
1# V8
2
3<!--introduced_in=v4.0.0-->
4
5<!-- source_link=lib/v8.js -->
6
7The `node:v8` module exposes APIs that are specific to the version of [V8][]
8built into the Node.js binary. It can be accessed using:
9
10```js
11const v8 = require('node:v8');
12```
13
14## `v8.cachedDataVersionTag()`
15
16<!-- YAML
17added: v8.0.0
18-->
19
20* Returns: {integer}
21
22Returns an integer representing a version tag derived from the V8 version,
23command-line flags, and detected CPU features. This is useful for determining
24whether a [`vm.Script`][] `cachedData` buffer is compatible with this instance
25of V8.
26
27```js
28console.log(v8.cachedDataVersionTag()); // 3947234607
29// The value returned by v8.cachedDataVersionTag() is derived from the V8
30// version, command-line flags, and detected CPU features. Test that the value
31// does indeed update when flags are toggled.
32v8.setFlagsFromString('--allow_natives_syntax');
33console.log(v8.cachedDataVersionTag()); // 183726201
34```
35
36## `v8.getHeapCodeStatistics()`
37
38<!-- YAML
39added: v12.8.0
40-->
41
42* Returns: {Object}
43
44Get statistics about code and its metadata in the heap, see V8
45[`GetHeapCodeAndMetadataStatistics`][] API. Returns an object with the
46following properties:
47
48* `code_and_metadata_size` {number}
49* `bytecode_and_metadata_size` {number}
50* `external_script_source_size` {number}
51* `cpu_profiler_metadata_size` {number}
52
53<!-- eslint-skip -->
54
55```js
56{
57  code_and_metadata_size: 212208,
58  bytecode_and_metadata_size: 161368,
59  external_script_source_size: 1410794,
60  cpu_profiler_metadata_size: 0,
61}
62```
63
64## `v8.getHeapSnapshot()`
65
66<!-- YAML
67added: v11.13.0
68-->
69
70* Returns: {stream.Readable} A Readable Stream containing the V8 heap snapshot
71
72Generates a snapshot of the current V8 heap and returns a Readable
73Stream that may be used to read the JSON serialized representation.
74This JSON stream format is intended to be used with tools such as
75Chrome DevTools. The JSON schema is undocumented and specific to the
76V8 engine. Therefore, the schema may change from one version of V8 to the next.
77
78Creating a heap snapshot requires memory about twice the size of the heap at
79the time the snapshot is created. This results in the risk of OOM killers
80terminating the process.
81
82Generating a snapshot is a synchronous operation which blocks the event loop
83for a duration depending on the heap size.
84
85```js
86// Print heap snapshot to the console
87const v8 = require('node:v8');
88const stream = v8.getHeapSnapshot();
89stream.pipe(process.stdout);
90```
91
92## `v8.getHeapSpaceStatistics()`
93
94<!-- YAML
95added: v6.0.0
96changes:
97  - version: v7.5.0
98    pr-url: https://github.com/nodejs/node/pull/10186
99    description: Support values exceeding the 32-bit unsigned integer range.
100-->
101
102* Returns: {Object\[]}
103
104Returns statistics about the V8 heap spaces, i.e. the segments which make up
105the V8 heap. Neither the ordering of heap spaces, nor the availability of a
106heap space can be guaranteed as the statistics are provided via the V8
107[`GetHeapSpaceStatistics`][] function and may change from one V8 version to the
108next.
109
110The value returned is an array of objects containing the following properties:
111
112* `space_name` {string}
113* `space_size` {number}
114* `space_used_size` {number}
115* `space_available_size` {number}
116* `physical_space_size` {number}
117
118```json
119[
120  {
121    "space_name": "new_space",
122    "space_size": 2063872,
123    "space_used_size": 951112,
124    "space_available_size": 80824,
125    "physical_space_size": 2063872
126  },
127  {
128    "space_name": "old_space",
129    "space_size": 3090560,
130    "space_used_size": 2493792,
131    "space_available_size": 0,
132    "physical_space_size": 3090560
133  },
134  {
135    "space_name": "code_space",
136    "space_size": 1260160,
137    "space_used_size": 644256,
138    "space_available_size": 960,
139    "physical_space_size": 1260160
140  },
141  {
142    "space_name": "map_space",
143    "space_size": 1094160,
144    "space_used_size": 201608,
145    "space_available_size": 0,
146    "physical_space_size": 1094160
147  },
148  {
149    "space_name": "large_object_space",
150    "space_size": 0,
151    "space_used_size": 0,
152    "space_available_size": 1490980608,
153    "physical_space_size": 0
154  }
155]
156```
157
158## `v8.getHeapStatistics()`
159
160<!-- YAML
161added: v1.0.0
162changes:
163  - version: v7.5.0
164    pr-url: https://github.com/nodejs/node/pull/10186
165    description: Support values exceeding the 32-bit unsigned integer range.
166  - version: v7.2.0
167    pr-url: https://github.com/nodejs/node/pull/8610
168    description: Added `malloced_memory`, `peak_malloced_memory`,
169                 and `does_zap_garbage`.
170-->
171
172* Returns: {Object}
173
174Returns an object with the following properties:
175
176* `total_heap_size` {number}
177* `total_heap_size_executable` {number}
178* `total_physical_size` {number}
179* `total_available_size` {number}
180* `used_heap_size` {number}
181* `heap_size_limit` {number}
182* `malloced_memory` {number}
183* `peak_malloced_memory` {number}
184* `does_zap_garbage` {number}
185* `number_of_native_contexts` {number}
186* `number_of_detached_contexts` {number}
187* `total_global_handles_size` {number}
188* `used_global_handles_size` {number}
189* `external_memory` {number}
190
191`does_zap_garbage` is a 0/1 boolean, which signifies whether the
192`--zap_code_space` option is enabled or not. This makes V8 overwrite heap
193garbage with a bit pattern. The RSS footprint (resident set size) gets bigger
194because it continuously touches all heap pages and that makes them less likely
195to get swapped out by the operating system.
196
197`number_of_native_contexts` The value of native\_context is the number of the
198top-level contexts currently active. Increase of this number over time indicates
199a memory leak.
200
201`number_of_detached_contexts` The value of detached\_context is the number
202of contexts that were detached and not yet garbage collected. This number
203being non-zero indicates a potential memory leak.
204
205`total_global_handles_size` The value of total\_global\_handles\_size is the
206total memory size of V8 global handles.
207
208`used_global_handles_size` The value of used\_global\_handles\_size is the
209used memory size of V8 global handles.
210
211`external_memory` The value of external\_memory is the memory size of array
212buffers and external strings.
213
214<!-- eslint-skip -->
215
216```js
217{
218  total_heap_size: 7326976,
219  total_heap_size_executable: 4194304,
220  total_physical_size: 7326976,
221  total_available_size: 1152656,
222  used_heap_size: 3476208,
223  heap_size_limit: 1535115264,
224  malloced_memory: 16384,
225  peak_malloced_memory: 1127496,
226  does_zap_garbage: 0,
227  number_of_native_contexts: 1,
228  number_of_detached_contexts: 0,
229  total_global_handles_size: 8192,
230  used_global_handles_size: 3296,
231  external_memory: 318824
232}
233```
234
235## `v8.setFlagsFromString(flags)`
236
237<!-- YAML
238added: v1.0.0
239-->
240
241* `flags` {string}
242
243The `v8.setFlagsFromString()` method can be used to programmatically set
244V8 command-line flags. This method should be used with care. Changing settings
245after the VM has started may result in unpredictable behavior, including
246crashes and data loss; or it may simply do nothing.
247
248The V8 options available for a version of Node.js may be determined by running
249`node --v8-options`.
250
251Usage:
252
253```js
254// Print GC events to stdout for one minute.
255const v8 = require('node:v8');
256v8.setFlagsFromString('--trace_gc');
257setTimeout(() => { v8.setFlagsFromString('--notrace_gc'); }, 60e3);
258```
259
260## `v8.stopCoverage()`
261
262<!-- YAML
263added:
264  - v15.1.0
265  - v14.18.0
266  - v12.22.0
267-->
268
269The `v8.stopCoverage()` method allows the user to stop the coverage collection
270started by [`NODE_V8_COVERAGE`][], so that V8 can release the execution count
271records and optimize code. This can be used in conjunction with
272[`v8.takeCoverage()`][] if the user wants to collect the coverage on demand.
273
274## `v8.takeCoverage()`
275
276<!-- YAML
277added:
278  - v15.1.0
279  - v14.18.0
280  - v12.22.0
281-->
282
283The `v8.takeCoverage()` method allows the user to write the coverage started by
284[`NODE_V8_COVERAGE`][] to disk on demand. This method can be invoked multiple
285times during the lifetime of the process. Each time the execution counter will
286be reset and a new coverage report will be written to the directory specified
287by [`NODE_V8_COVERAGE`][].
288
289When the process is about to exit, one last coverage will still be written to
290disk unless [`v8.stopCoverage()`][] is invoked before the process exits.
291
292## `v8.writeHeapSnapshot([filename])`
293
294<!-- YAML
295added: v11.13.0
296changes:
297  - version: v18.0.0
298    pr-url: https://github.com/nodejs/node/pull/41373
299    description: An exception will now be thrown if the file could not be written.
300  - version: v18.0.0
301    pr-url: https://github.com/nodejs/node/pull/42577
302    description: Make the returned error codes consistent across all platforms.
303-->
304
305* `filename` {string} The file path where the V8 heap snapshot is to be
306  saved. If not specified, a file name with the pattern
307  `'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot'` will be
308  generated, where `{pid}` will be the PID of the Node.js process,
309  `{thread_id}` will be `0` when `writeHeapSnapshot()` is called from
310  the main Node.js thread or the id of a worker thread.
311* Returns: {string} The filename where the snapshot was saved.
312
313Generates a snapshot of the current V8 heap and writes it to a JSON
314file. This file is intended to be used with tools such as Chrome
315DevTools. The JSON schema is undocumented and specific to the V8
316engine, and may change from one version of V8 to the next.
317
318A heap snapshot is specific to a single V8 isolate. When using
319[worker threads][], a heap snapshot generated from the main thread will
320not contain any information about the workers, and vice versa.
321
322Creating a heap snapshot requires memory about twice the size of the heap at
323the time the snapshot is created. This results in the risk of OOM killers
324terminating the process.
325
326Generating a snapshot is a synchronous operation which blocks the event loop
327for a duration depending on the heap size.
328
329```js
330const { writeHeapSnapshot } = require('node:v8');
331const {
332  Worker,
333  isMainThread,
334  parentPort,
335} = require('node:worker_threads');
336
337if (isMainThread) {
338  const worker = new Worker(__filename);
339
340  worker.once('message', (filename) => {
341    console.log(`worker heapdump: ${filename}`);
342    // Now get a heapdump for the main thread.
343    console.log(`main thread heapdump: ${writeHeapSnapshot()}`);
344  });
345
346  // Tell the worker to create a heapdump.
347  worker.postMessage('heapdump');
348} else {
349  parentPort.once('message', (message) => {
350    if (message === 'heapdump') {
351      // Generate a heapdump for the worker
352      // and return the filename to the parent.
353      parentPort.postMessage(writeHeapSnapshot());
354    }
355  });
356}
357```
358
359## `v8.setHeapSnapshotNearHeapLimit(limit)`
360
361<!-- YAML
362added: v18.10.0
363-->
364
365> Stability: 1 - Experimental
366
367* `limit` {integer}
368
369The API is a no-op if `--heapsnapshot-near-heap-limit` is already set from the
370command line or the API is called more than once. `limit` must be a positive
371integer. See [`--heapsnapshot-near-heap-limit`][] for more information.
372
373## Serialization API
374
375The serialization API provides means of serializing JavaScript values in a way
376that is compatible with the [HTML structured clone algorithm][].
377
378The format is backward-compatible (i.e. safe to store to disk).
379Equal JavaScript values may result in different serialized output.
380
381### `v8.serialize(value)`
382
383<!-- YAML
384added: v8.0.0
385-->
386
387* `value` {any}
388* Returns: {Buffer}
389
390Uses a [`DefaultSerializer`][] to serialize `value` into a buffer.
391
392[`ERR_BUFFER_TOO_LARGE`][] will be thrown when trying to
393serialize a huge object which requires buffer
394larger than [`buffer.constants.MAX_LENGTH`][].
395
396### `v8.deserialize(buffer)`
397
398<!-- YAML
399added: v8.0.0
400-->
401
402* `buffer` {Buffer|TypedArray|DataView} A buffer returned by [`serialize()`][].
403
404Uses a [`DefaultDeserializer`][] with default options to read a JS value
405from a buffer.
406
407### Class: `v8.Serializer`
408
409<!-- YAML
410added: v8.0.0
411-->
412
413#### `new Serializer()`
414
415Creates a new `Serializer` object.
416
417#### `serializer.writeHeader()`
418
419Writes out a header, which includes the serialization format version.
420
421#### `serializer.writeValue(value)`
422
423* `value` {any}
424
425Serializes a JavaScript value and adds the serialized representation to the
426internal buffer.
427
428This throws an error if `value` cannot be serialized.
429
430#### `serializer.releaseBuffer()`
431
432* Returns: {Buffer}
433
434Returns the stored internal buffer. This serializer should not be used once
435the buffer is released. Calling this method results in undefined behavior
436if a previous write has failed.
437
438#### `serializer.transferArrayBuffer(id, arrayBuffer)`
439
440* `id` {integer} A 32-bit unsigned integer.
441* `arrayBuffer` {ArrayBuffer} An `ArrayBuffer` instance.
442
443Marks an `ArrayBuffer` as having its contents transferred out of band.
444Pass the corresponding `ArrayBuffer` in the deserializing context to
445[`deserializer.transferArrayBuffer()`][].
446
447#### `serializer.writeUint32(value)`
448
449* `value` {integer}
450
451Write a raw 32-bit unsigned integer.
452For use inside of a custom [`serializer._writeHostObject()`][].
453
454#### `serializer.writeUint64(hi, lo)`
455
456* `hi` {integer}
457* `lo` {integer}
458
459Write a raw 64-bit unsigned integer, split into high and low 32-bit parts.
460For use inside of a custom [`serializer._writeHostObject()`][].
461
462#### `serializer.writeDouble(value)`
463
464* `value` {number}
465
466Write a JS `number` value.
467For use inside of a custom [`serializer._writeHostObject()`][].
468
469#### `serializer.writeRawBytes(buffer)`
470
471* `buffer` {Buffer|TypedArray|DataView}
472
473Write raw bytes into the serializer's internal buffer. The deserializer
474will require a way to compute the length of the buffer.
475For use inside of a custom [`serializer._writeHostObject()`][].
476
477#### `serializer._writeHostObject(object)`
478
479* `object` {Object}
480
481This method is called to write some kind of host object, i.e. an object created
482by native C++ bindings. If it is not possible to serialize `object`, a suitable
483exception should be thrown.
484
485This method is not present on the `Serializer` class itself but can be provided
486by subclasses.
487
488#### `serializer._getDataCloneError(message)`
489
490* `message` {string}
491
492This method is called to generate error objects that will be thrown when an
493object can not be cloned.
494
495This method defaults to the [`Error`][] constructor and can be overridden on
496subclasses.
497
498#### `serializer._getSharedArrayBufferId(sharedArrayBuffer)`
499
500* `sharedArrayBuffer` {SharedArrayBuffer}
501
502This method is called when the serializer is going to serialize a
503`SharedArrayBuffer` object. It must return an unsigned 32-bit integer ID for
504the object, using the same ID if this `SharedArrayBuffer` has already been
505serialized. When deserializing, this ID will be passed to
506[`deserializer.transferArrayBuffer()`][].
507
508If the object cannot be serialized, an exception should be thrown.
509
510This method is not present on the `Serializer` class itself but can be provided
511by subclasses.
512
513#### `serializer._setTreatArrayBufferViewsAsHostObjects(flag)`
514
515* `flag` {boolean} **Default:** `false`
516
517Indicate whether to treat `TypedArray` and `DataView` objects as
518host objects, i.e. pass them to [`serializer._writeHostObject()`][].
519
520### Class: `v8.Deserializer`
521
522<!-- YAML
523added: v8.0.0
524-->
525
526#### `new Deserializer(buffer)`
527
528* `buffer` {Buffer|TypedArray|DataView} A buffer returned by
529  [`serializer.releaseBuffer()`][].
530
531Creates a new `Deserializer` object.
532
533#### `deserializer.readHeader()`
534
535Reads and validates a header (including the format version).
536May, for example, reject an invalid or unsupported wire format. In that case,
537an `Error` is thrown.
538
539#### `deserializer.readValue()`
540
541Deserializes a JavaScript value from the buffer and returns it.
542
543#### `deserializer.transferArrayBuffer(id, arrayBuffer)`
544
545* `id` {integer} A 32-bit unsigned integer.
546* `arrayBuffer` {ArrayBuffer|SharedArrayBuffer} An `ArrayBuffer` instance.
547
548Marks an `ArrayBuffer` as having its contents transferred out of band.
549Pass the corresponding `ArrayBuffer` in the serializing context to
550[`serializer.transferArrayBuffer()`][] (or return the `id` from
551[`serializer._getSharedArrayBufferId()`][] in the case of `SharedArrayBuffer`s).
552
553#### `deserializer.getWireFormatVersion()`
554
555* Returns: {integer}
556
557Reads the underlying wire format version. Likely mostly to be useful to
558legacy code reading old wire format versions. May not be called before
559`.readHeader()`.
560
561#### `deserializer.readUint32()`
562
563* Returns: {integer}
564
565Read a raw 32-bit unsigned integer and return it.
566For use inside of a custom [`deserializer._readHostObject()`][].
567
568#### `deserializer.readUint64()`
569
570* Returns: {integer\[]}
571
572Read a raw 64-bit unsigned integer and return it as an array `[hi, lo]`
573with two 32-bit unsigned integer entries.
574For use inside of a custom [`deserializer._readHostObject()`][].
575
576#### `deserializer.readDouble()`
577
578* Returns: {number}
579
580Read a JS `number` value.
581For use inside of a custom [`deserializer._readHostObject()`][].
582
583#### `deserializer.readRawBytes(length)`
584
585* `length` {integer}
586* Returns: {Buffer}
587
588Read raw bytes from the deserializer's internal buffer. The `length` parameter
589must correspond to the length of the buffer that was passed to
590[`serializer.writeRawBytes()`][].
591For use inside of a custom [`deserializer._readHostObject()`][].
592
593#### `deserializer._readHostObject()`
594
595This method is called to read some kind of host object, i.e. an object that is
596created by native C++ bindings. If it is not possible to deserialize the data,
597a suitable exception should be thrown.
598
599This method is not present on the `Deserializer` class itself but can be
600provided by subclasses.
601
602### Class: `v8.DefaultSerializer`
603
604<!-- YAML
605added: v8.0.0
606-->
607
608A subclass of [`Serializer`][] that serializes `TypedArray`
609(in particular [`Buffer`][]) and `DataView` objects as host objects, and only
610stores the part of their underlying `ArrayBuffer`s that they are referring to.
611
612### Class: `v8.DefaultDeserializer`
613
614<!-- YAML
615added: v8.0.0
616-->
617
618A subclass of [`Deserializer`][] corresponding to the format written by
619[`DefaultSerializer`][].
620
621## Promise hooks
622
623The `promiseHooks` interface can be used to track promise lifecycle events.
624To track _all_ async activity, see [`async_hooks`][] which internally uses this
625module to produce promise lifecycle events in addition to events for other
626async resources. For request context management, see [`AsyncLocalStorage`][].
627
628```mjs
629import { promiseHooks } from 'node:v8';
630
631// There are four lifecycle events produced by promises:
632
633// The `init` event represents the creation of a promise. This could be a
634// direct creation such as with `new Promise(...)` or a continuation such
635// as `then()` or `catch()`. It also happens whenever an async function is
636// called or does an `await`. If a continuation promise is created, the
637// `parent` will be the promise it is a continuation from.
638function init(promise, parent) {
639  console.log('a promise was created', { promise, parent });
640}
641
642// The `settled` event happens when a promise receives a resolution or
643// rejection value. This may happen synchronously such as when using
644// `Promise.resolve()` on non-promise input.
645function settled(promise) {
646  console.log('a promise resolved or rejected', { promise });
647}
648
649// The `before` event runs immediately before a `then()` or `catch()` handler
650// runs or an `await` resumes execution.
651function before(promise) {
652  console.log('a promise is about to call a then handler', { promise });
653}
654
655// The `after` event runs immediately after a `then()` handler runs or when
656// an `await` begins after resuming from another.
657function after(promise) {
658  console.log('a promise is done calling a then handler', { promise });
659}
660
661// Lifecycle hooks may be started and stopped individually
662const stopWatchingInits = promiseHooks.onInit(init);
663const stopWatchingSettleds = promiseHooks.onSettled(settled);
664const stopWatchingBefores = promiseHooks.onBefore(before);
665const stopWatchingAfters = promiseHooks.onAfter(after);
666
667// Or they may be started and stopped in groups
668const stopHookSet = promiseHooks.createHook({
669  init,
670  settled,
671  before,
672  after,
673});
674
675// To stop a hook, call the function returned at its creation.
676stopWatchingInits();
677stopWatchingSettleds();
678stopWatchingBefores();
679stopWatchingAfters();
680stopHookSet();
681```
682
683### `promiseHooks.onInit(init)`
684
685<!-- YAML
686added:
687  - v17.1.0
688  - v16.14.0
689-->
690
691* `init` {Function} The [`init` callback][] to call when a promise is created.
692* Returns: {Function} Call to stop the hook.
693
694**The `init` hook must be a plain function. Providing an async function will
695throw as it would produce an infinite microtask loop.**
696
697```mjs
698import { promiseHooks } from 'node:v8';
699
700const stop = promiseHooks.onInit((promise, parent) => {});
701```
702
703```cjs
704const { promiseHooks } = require('node:v8');
705
706const stop = promiseHooks.onInit((promise, parent) => {});
707```
708
709### `promiseHooks.onSettled(settled)`
710
711<!-- YAML
712added:
713  - v17.1.0
714  - v16.14.0
715-->
716
717* `settled` {Function} The [`settled` callback][] to call when a promise
718  is resolved or rejected.
719* Returns: {Function} Call to stop the hook.
720
721**The `settled` hook must be a plain function. Providing an async function will
722throw as it would produce an infinite microtask loop.**
723
724```mjs
725import { promiseHooks } from 'node:v8';
726
727const stop = promiseHooks.onSettled((promise) => {});
728```
729
730```cjs
731const { promiseHooks } = require('node:v8');
732
733const stop = promiseHooks.onSettled((promise) => {});
734```
735
736### `promiseHooks.onBefore(before)`
737
738<!-- YAML
739added:
740  - v17.1.0
741  - v16.14.0
742-->
743
744* `before` {Function} The [`before` callback][] to call before a promise
745  continuation executes.
746* Returns: {Function} Call to stop the hook.
747
748**The `before` hook must be a plain function. Providing an async function will
749throw as it would produce an infinite microtask loop.**
750
751```mjs
752import { promiseHooks } from 'node:v8';
753
754const stop = promiseHooks.onBefore((promise) => {});
755```
756
757```cjs
758const { promiseHooks } = require('node:v8');
759
760const stop = promiseHooks.onBefore((promise) => {});
761```
762
763### `promiseHooks.onAfter(after)`
764
765<!-- YAML
766added:
767  - v17.1.0
768  - v16.14.0
769-->
770
771* `after` {Function} The [`after` callback][] to call after a promise
772  continuation executes.
773* Returns: {Function} Call to stop the hook.
774
775**The `after` hook must be a plain function. Providing an async function will
776throw as it would produce an infinite microtask loop.**
777
778```mjs
779import { promiseHooks } from 'node:v8';
780
781const stop = promiseHooks.onAfter((promise) => {});
782```
783
784```cjs
785const { promiseHooks } = require('node:v8');
786
787const stop = promiseHooks.onAfter((promise) => {});
788```
789
790### `promiseHooks.createHook(callbacks)`
791
792<!-- YAML
793added:
794  - v17.1.0
795  - v16.14.0
796-->
797
798* `callbacks` {Object} The [Hook Callbacks][] to register
799  * `init` {Function} The [`init` callback][].
800  * `before` {Function} The [`before` callback][].
801  * `after` {Function} The [`after` callback][].
802  * `settled` {Function} The [`settled` callback][].
803* Returns: {Function} Used for disabling hooks
804
805**The hook callbacks must be plain functions. Providing async functions will
806throw as it would produce an infinite microtask loop.**
807
808Registers functions to be called for different lifetime events of each promise.
809
810The callbacks `init()`/`before()`/`after()`/`settled()` are called for the
811respective events during a promise's lifetime.
812
813All callbacks are optional. For example, if only promise creation needs to
814be tracked, then only the `init` callback needs to be passed. The
815specifics of all functions that can be passed to `callbacks` is in the
816[Hook Callbacks][] section.
817
818```mjs
819import { promiseHooks } from 'node:v8';
820
821const stopAll = promiseHooks.createHook({
822  init(promise, parent) {},
823});
824```
825
826```cjs
827const { promiseHooks } = require('node:v8');
828
829const stopAll = promiseHooks.createHook({
830  init(promise, parent) {},
831});
832```
833
834### Hook callbacks
835
836Key events in the lifetime of a promise have been categorized into four areas:
837creation of a promise, before/after a continuation handler is called or around
838an await, and when the promise resolves or rejects.
839
840While these hooks are similar to those of [`async_hooks`][] they lack a
841`destroy` hook. Other types of async resources typically represent sockets or
842file descriptors which have a distinct "closed" state to express the `destroy`
843lifecycle event while promises remain usable for as long as code can still
844reach them. Garbage collection tracking is used to make promises fit into the
845`async_hooks` event model, however this tracking is very expensive and they may
846not necessarily ever even be garbage collected.
847
848Because promises are asynchronous resources whose lifecycle is tracked
849via the promise hooks mechanism, the `init()`, `before()`, `after()`, and
850`settled()` callbacks _must not_ be async functions as they create more
851promises which would produce an infinite loop.
852
853While this API is used to feed promise events into [`async_hooks`][], the
854ordering between the two is undefined. Both APIs are multi-tenant
855and therefore could produce events in any order relative to each other.
856
857#### `init(promise, parent)`
858
859* `promise` {Promise} The promise being created.
860* `parent` {Promise} The promise continued from, if applicable.
861
862Called when a promise is constructed. This _does not_ mean that corresponding
863`before`/`after` events will occur, only that the possibility exists. This will
864happen if a promise is created without ever getting a continuation.
865
866#### `before(promise)`
867
868* `promise` {Promise}
869
870Called before a promise continuation executes. This can be in the form of
871`then()`, `catch()`, or `finally()` handlers or an `await` resuming.
872
873The `before` callback will be called 0 to N times. The `before` callback
874will typically be called 0 times if no continuation was ever made for the
875promise. The `before` callback may be called many times in the case where
876many continuations have been made from the same promise.
877
878#### `after(promise)`
879
880* `promise` {Promise}
881
882Called immediately after a promise continuation executes. This may be after a
883`then()`, `catch()`, or `finally()` handler or before an `await` after another
884`await`.
885
886#### `settled(promise)`
887
888* `promise` {Promise}
889
890Called when the promise receives a resolution or rejection value. This may
891occur synchronously in the case of `Promise.resolve()` or `Promise.reject()`.
892
893## Startup Snapshot API
894
895<!-- YAML
896added: v18.6.0
897-->
898
899> Stability: 1 - Experimental
900
901The `v8.startupSnapshot` interface can be used to add serialization and
902deserialization hooks for custom startup snapshots.
903
904```console
905$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
906# This launches a process with the snapshot
907$ node --snapshot-blob snapshot.blob
908```
909
910In the example above, `entry.js` can use methods from the `v8.startupSnapshot`
911interface to specify how to save information for custom objects in the snapshot
912during serialization and how the information can be used to synchronize these
913objects during deserialization of the snapshot. For example, if the `entry.js`
914contains the following script:
915
916```cjs
917'use strict';
918
919const fs = require('node:fs');
920const zlib = require('node:zlib');
921const path = require('node:path');
922const assert = require('node:assert');
923
924const v8 = require('node:v8');
925
926class BookShelf {
927  storage = new Map();
928
929  // Reading a series of files from directory and store them into storage.
930  constructor(directory, books) {
931    for (const book of books) {
932      this.storage.set(book, fs.readFileSync(path.join(directory, book)));
933    }
934  }
935
936  static compressAll(shelf) {
937    for (const [ book, content ] of shelf.storage) {
938      shelf.storage.set(book, zlib.gzipSync(content));
939    }
940  }
941
942  static decompressAll(shelf) {
943    for (const [ book, content ] of shelf.storage) {
944      shelf.storage.set(book, zlib.gunzipSync(content));
945    }
946  }
947}
948
949// __dirname here is where the snapshot script is placed
950// during snapshot building time.
951const shelf = new BookShelf(__dirname, [
952  'book1.en_US.txt',
953  'book1.es_ES.txt',
954  'book2.zh_CN.txt',
955]);
956
957assert(v8.startupSnapshot.isBuildingSnapshot());
958// On snapshot serialization, compress the books to reduce size.
959v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
960// On snapshot deserialization, decompress the books.
961v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
962v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
963  // process.env and process.argv are refreshed during snapshot
964  // deserialization.
965  const lang = process.env.BOOK_LANG || 'en_US';
966  const book = process.argv[1];
967  const name = `${book}.${lang}.txt`;
968  console.log(shelf.storage.get(name));
969}, shelf);
970```
971
972The resulted binary will get print the data deserialized from the snapshot
973during start up, using the refreshed `process.env` and `process.argv` of
974the launched process:
975
976```console
977$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1
978# Prints content of book1.es_ES.txt deserialized from the snapshot.
979```
980
981Currently the application deserialized from a user-land snapshot cannot
982be snapshotted again, so these APIs are only available to applications
983that are not deserialized from a user-land snapshot.
984
985### `v8.startupSnapshot.addSerializeCallback(callback[, data])`
986
987<!-- YAML
988added: v18.6.0
989-->
990
991* `callback` {Function} Callback to be invoked before serialization.
992* `data` {any} Optional data that will be passed to the `callback` when it
993  gets called.
994
995Add a callback that will be called when the Node.js instance is about to
996get serialized into a snapshot and exit. This can be used to release
997resources that should not or cannot be serialized or to convert user data
998into a form more suitable for serialization.
999
1000### `v8.startupSnapshot.addDeserializeCallback(callback[, data])`
1001
1002<!-- YAML
1003added: v18.6.0
1004-->
1005
1006* `callback` {Function} Callback to be invoked after the snapshot is
1007  deserialized.
1008* `data` {any} Optional data that will be passed to the `callback` when it
1009  gets called.
1010
1011Add a callback that will be called when the Node.js instance is deserialized
1012from a snapshot. The `callback` and the `data` (if provided) will be
1013serialized into the snapshot, they can be used to re-initialize the state
1014of the application or to re-acquire resources that the application needs
1015when the application is restarted from the snapshot.
1016
1017### `v8.startupSnapshot.setDeserializeMainFunction(callback[, data])`
1018
1019<!-- YAML
1020added: v18.6.0
1021-->
1022
1023* `callback` {Function} Callback to be invoked as the entry point after the
1024  snapshot is deserialized.
1025* `data` {any} Optional data that will be passed to the `callback` when it
1026  gets called.
1027
1028This sets the entry point of the Node.js application when it is deserialized
1029from a snapshot. This can be called only once in the snapshot building
1030script. If called, the deserialized application no longer needs an additional
1031entry point script to start up and will simply invoke the callback along with
1032the deserialized data (if provided), otherwise an entry point script still
1033needs to be provided to the deserialized application.
1034
1035### `v8.startupSnapshot.isBuildingSnapshot()`
1036
1037<!-- YAML
1038added: v18.6.0
1039-->
1040
1041* Returns: {boolean}
1042
1043Returns true if the Node.js instance is run to build a snapshot.
1044
1045## Class: `v8.GCProfiler`
1046
1047<!-- YAML
1048added: v18.15.0
1049-->
1050
1051This API collects GC data in current thread.
1052
1053### `new v8.GCProfiler()`
1054
1055<!-- YAML
1056added: v18.15.0
1057-->
1058
1059Create a new instance of the `v8.GCProfiler` class.
1060
1061### `profiler.start()`
1062
1063<!-- YAML
1064added: v18.15.0
1065-->
1066
1067Start collecting GC data.
1068
1069### `profiler.stop()`
1070
1071<!-- YAML
1072added: v18.15.0
1073-->
1074
1075Stop collecting GC data and return an object.The content of object
1076is as follows.
1077
1078```json
1079{
1080  "version": 1,
1081  "startTime": 1674059033862,
1082  "statistics": [
1083    {
1084      "gcType": "Scavenge",
1085      "beforeGC": {
1086        "heapStatistics": {
1087          "totalHeapSize": 5005312,
1088          "totalHeapSizeExecutable": 524288,
1089          "totalPhysicalSize": 5226496,
1090          "totalAvailableSize": 4341325216,
1091          "totalGlobalHandlesSize": 8192,
1092          "usedGlobalHandlesSize": 2112,
1093          "usedHeapSize": 4883840,
1094          "heapSizeLimit": 4345298944,
1095          "mallocedMemory": 254128,
1096          "externalMemory": 225138,
1097          "peakMallocedMemory": 181760
1098        },
1099        "heapSpaceStatistics": [
1100          {
1101            "spaceName": "read_only_space",
1102            "spaceSize": 0,
1103            "spaceUsedSize": 0,
1104            "spaceAvailableSize": 0,
1105            "physicalSpaceSize": 0
1106          }
1107        ]
1108      },
1109      "cost": 1574.14,
1110      "afterGC": {
1111        "heapStatistics": {
1112          "totalHeapSize": 6053888,
1113          "totalHeapSizeExecutable": 524288,
1114          "totalPhysicalSize": 5500928,
1115          "totalAvailableSize": 4341101384,
1116          "totalGlobalHandlesSize": 8192,
1117          "usedGlobalHandlesSize": 2112,
1118          "usedHeapSize": 4059096,
1119          "heapSizeLimit": 4345298944,
1120          "mallocedMemory": 254128,
1121          "externalMemory": 225138,
1122          "peakMallocedMemory": 181760
1123        },
1124        "heapSpaceStatistics": [
1125          {
1126            "spaceName": "read_only_space",
1127            "spaceSize": 0,
1128            "spaceUsedSize": 0,
1129            "spaceAvailableSize": 0,
1130            "physicalSpaceSize": 0
1131          }
1132        ]
1133      }
1134    }
1135  ],
1136  "endTime": 1674059036865
1137}
1138```
1139
1140Here's an example.
1141
1142```js
1143const { GCProfiler } = require('v8');
1144const profiler = new GCProfiler();
1145profiler.start();
1146setTimeout(() => {
1147  console.log(profiler.stop());
1148}, 1000);
1149```
1150
1151[HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
1152[Hook Callbacks]: #hook-callbacks
1153[V8]: https://developers.google.com/v8/
1154[`--heapsnapshot-near-heap-limit`]: cli.md#--heapsnapshot-near-heap-limitmax_count
1155[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
1156[`Buffer`]: buffer.md
1157[`DefaultDeserializer`]: #class-v8defaultdeserializer
1158[`DefaultSerializer`]: #class-v8defaultserializer
1159[`Deserializer`]: #class-v8deserializer
1160[`ERR_BUFFER_TOO_LARGE`]: errors.md#err_buffer_too_large
1161[`Error`]: errors.md#class-error
1162[`GetHeapCodeAndMetadataStatistics`]: https://v8docs.nodesource.com/node-13.2/d5/dda/classv8_1_1_isolate.html#a6079122af17612ef54ef3348ce170866
1163[`GetHeapSpaceStatistics`]: https://v8docs.nodesource.com/node-13.2/d5/dda/classv8_1_1_isolate.html#ac673576f24fdc7a33378f8f57e1d13a4
1164[`NODE_V8_COVERAGE`]: cli.md#node_v8_coveragedir
1165[`Serializer`]: #class-v8serializer
1166[`after` callback]: #afterpromise
1167[`async_hooks`]: async_hooks.md
1168[`before` callback]: #beforepromise
1169[`buffer.constants.MAX_LENGTH`]: buffer.md#bufferconstantsmax_length
1170[`deserializer._readHostObject()`]: #deserializer_readhostobject
1171[`deserializer.transferArrayBuffer()`]: #deserializertransferarraybufferid-arraybuffer
1172[`init` callback]: #initpromise-parent
1173[`serialize()`]: #v8serializevalue
1174[`serializer._getSharedArrayBufferId()`]: #serializer_getsharedarraybufferidsharedarraybuffer
1175[`serializer._writeHostObject()`]: #serializer_writehostobjectobject
1176[`serializer.releaseBuffer()`]: #serializerreleasebuffer
1177[`serializer.transferArrayBuffer()`]: #serializertransferarraybufferid-arraybuffer
1178[`serializer.writeRawBytes()`]: #serializerwriterawbytesbuffer
1179[`settled` callback]: #settledpromise
1180[`v8.stopCoverage()`]: #v8stopcoverage
1181[`v8.takeCoverage()`]: #v8takecoverage
1182[`vm.Script`]: vm.md#new-vmscriptcode-options
1183[worker threads]: worker_threads.md
1184