V8
Исходный код: lib/v8.js
Модуль node:v8 предоставляет API, специфичные для версии V8, встроенной в бинарный файл Node.js. Доступ к нему можно получить с помощью:
Модули JavaScript
import v8 from 'node:v8';
CommonJS
const v8 = require('node:v8');
v8.cachedDataVersionTag()
- Возвращает: <integer>
Возвращает целое число, представляющее тег версии, полученный на основе версии V8, флагов командной строки и обнаруженных возможностей ЦП. Это полезно для определения того, совместим ли буфер vm.Script cachedData с данным экземпляром V8.
console.log(v8.cachedDataVersionTag()); // 3947234607
// The value returned by v8.cachedDataVersionTag() is derived from the V8
// version, command-line flags, and detected CPU features. Test that the value
// does indeed update when flags are toggled.
v8.setFlagsFromString('--allow_natives_syntax');
console.log(v8.cachedDataVersionTag()); // 183726201 copy
v8.getHeapCodeStatistics()
- Возвращает: <Object>
Получает статистику о коде и его метаданных в куче, см. API V8 GetHeapCodeAndMetadataStatistics. Возвращает объект со следующими свойствами:
-
code_and_metadata_size<number> -
bytecode_and_metadata_size<number> -
external_script_source_size<number> -
cpu_profiler_metadata_size<number>
{
code_and_metadata_size: 212208,
bytecode_and_metadata_size: 161368,
external_script_source_size: 1410794,
cpu_profiler_metadata_size: 0,
} copy
v8.getHeapSnapshot([options])
-
options<Object> -
Возвращает: <stream.Readable> Поток Readable, содержащий снимок кучи V8.
Создает снимок текущей кучи V8 и возвращает поток Readable, который можно использовать для чтения сериализованного в JSON представления. Этот формат потока JSON предназначен для использования с такими инструментами, как Chrome DevTools. Схема JSON не документирована и специфична для движка V8. Поэтому схема может меняться от одной версии V8 к другой.
Для создания снимка кучи требуется объем памяти, примерно вдвое превышающий размер кучи на момент создания снимка. Это создает риск завершения процесса средствами OOM killer.
Создание снимка — синхронная операция, которая блокирует цикл событий на время, зависящее от размера кучи.
// Print heap snapshot to the console
import { getHeapSnapshot } from 'node:v8';
import process from 'node:process';
const stream = getHeapSnapshot();
stream.pipe(process.stdout); copy // Print heap snapshot to the console
const v8 = require('node:v8');
const process = require('node:process');
const stream = v8.getHeapSnapshot();
stream.pipe(process.stdout); copy
v8.getHeapSpaceStatistics()
- Возвращает: <Object[]>
Возвращает статистику о пространствах кучи V8, то есть сегментах, из которых состоит куча V8. Ни порядок пространств кучи, ни наличие определенного пространства не гарантируются, поскольку статистика предоставляется функцией V8 GetHeapSpaceStatistics и может меняться от одной версии V8 к другой.
Возвращаемое значение — это массив объектов со следующими свойствами:
-
space_name<string> -
space_size<number> -
space_used_size<number> -
space_available_size<number> -
physical_space_size<number>
[
{
"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
}
] copy
v8.getHeapStatistics()
- Возвращает: <Object>
Возвращает объект со следующими свойствами:
-
total_heap_size<number> -
total_heap_size_executable<number> -
total_physical_size<number> -
total_available_size<number> -
used_heap_size<number> -
heap_size_limit<number> -
malloced_memory<number> -
peak_malloced_memory<number> -
does_zap_garbage<number> -
number_of_native_contexts<number> -
number_of_detached_contexts<number> -
total_global_handles_size<number> -
used_global_handles_size<number> -
external_memory<number>
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 — это количество байтов, используемых в данный момент объектами JavaScript в V8. Это фактически используемая память; сюда не входит память, которая была выделена, но еще не использована.
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 (resident set size) увеличивается, поскольку происходит постоянное обращение ко всем страницам кучи, из-за чего операционная система с меньшей вероятностью выгрузит их в файл подкачки.
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 — это размер памяти буферов массивов и внешних строк.
{
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
} copy
v8.getCppHeapStatistics([detailLevel])
Получает статистику CppHeap о потреблении и использовании памяти с помощью функции V8 CollectStatistics(), которая может меняться от одной версии V8 к другой.
-
detailLevel<string> | <undefined>: По умолчанию:'detailed'. Указывает уровень детализации возвращаемой статистики. Допустимые значения:-
'brief': Краткая статистика содержит только сводные данные об объеме выделенной и используемой памяти для всей кучи. -
'detailed': Подробная статистика также содержит разбивку по областям и страницам, а также статистику списков свободных блоков и гистограммы типов объектов.
-
Метод возвращает объект со структурой, аналогичной объекту cppgc::HeapStatistics. Подробнее о свойствах объекта см. в документации V8.
// Detailed
({
committed_size_bytes: 131072,
resident_size_bytes: 131072,
used_size_bytes: 152,
space_statistics: [
{
name: 'NormalPageSpace0',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'NormalPageSpace1',
committed_size_bytes: 131072,
resident_size_bytes: 131072,
used_size_bytes: 152,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'NormalPageSpace2',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'NormalPageSpace3',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
{
name: 'LargePageSpace',
committed_size_bytes: 0,
resident_size_bytes: 0,
used_size_bytes: 0,
page_stats: [{}],
free_list_stats: {},
},
],
type_names: [],
detail_level: 'detailed',
}); copy // Brief
({
committed_size_bytes: 131072,
resident_size_bytes: 131072,
used_size_bytes: 128864,
space_statistics: [],
type_names: [],
detail_level: 'brief',
}); copy
v8.queryObjects(ctor[, options])
-
ctor<Function> Конструктор, который можно использовать для поиска в цепочке прототипов, чтобы отфильтровать целевые объекты в куче. -
options<undefined> | <Object>-
format<string> Если значение равно'count', возвращается количество найденных объектов. Если значение равно'summary', возвращается массив строк со сводной информацией о найденных объектах.
-
- Возвращает: {number|Array
}
Этот метод аналогичен API консоли Chromium DevTools queryObjects(). Его можно использовать для поиска в куче объектов, у которых в цепочке прототипов есть соответствующий конструктор, после полной сборки мусора. Это может быть полезно при регрессионном тестировании утечек памяти. Чтобы избежать неожиданных результатов, пользователям не следует применять этот API к конструкторам, реализацию которых они не контролируют, или к конструкторам, которые могут вызываться другими участниками приложения.
Чтобы избежать случайных утечек, этот API не возвращает прямые ссылки на найденные объекты. По умолчанию он возвращает количество найденных объектов. Если options.format равно 'summary', возвращается массив с краткими строковыми представлениями каждого объекта. Доступ к данным, предоставляемый этим API, аналогичен доступу, который дает снимок кучи, но позволяет избежать затрат на сериализацию и разбор данных и напрямую фильтровать целевые объекты в процессе поиска.
В результаты включаются только объекты, созданные в текущем контексте выполнения.
CommonJS
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' }));Модули JavaScript
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)
-
flags<string>
Метод v8.setFlagsFromString() можно использовать для программной установки флагов командной строки V8. Этот метод следует применять с осторожностью. Изменение настроек после запуска виртуальной машины может привести к непредсказуемому поведению, включая аварийное завершение работы и потерю данных; также метод может просто ничего не сделать.
Список параметров V8, доступных в конкретной версии Node.js, можно получить, запустив node --v8-options.
Использование:
Модули JavaScript
import { setFlagsFromString } from 'node:v8';
import { setInterval } from 'node:timers';
// setFlagsFromString to trace garbage collection events
setFlagsFromString('--trace-gc');
// Trigger GC events by using some memory
let arrays = [];
const interval = setInterval(() => {
for (let i = 0; i < 500; i++) {
arrays.push(new Array(10000).fill(Math.random()));
}
if (arrays.length > 5000) {
arrays = arrays.slice(-1000);
}
console.log(`\n* Created ${arrays.length} arrays\n`);
}, 100);
// setFlagsFromString to stop tracing GC events after 1.5 seconds
setTimeout(() => {
setFlagsFromString('--notrace-gc');
console.log('\nStopped tracing!\n');
}, 1500);
// Stop triggering GC events altogether after 2.5 seconds
setTimeout(() => {
clearInterval(interval);
}, 2500);CommonJS
const { setFlagsFromString } = require('node:v8');
const { setInterval } = require('node:timers');
// setFlagsFromString to trace garbage collection events
setFlagsFromString('--trace-gc');
// Trigger GC events by using some memory
let arrays = [];
const interval = setInterval(() => {
for (let i = 0; i < 500; i++) {
arrays.push(new Array(10000).fill(Math.random()));
}
if (arrays.length > 5000) {
arrays = arrays.slice(-1000);
}
console.log(`\n* Created ${arrays.length} arrays\n`);
}, 100);
// setFlagsFromString to stop tracing GC events after 1.5 seconds
setTimeout(() => {
console.log('\nStopped tracing!\n');
setFlagsFromString('--notrace-gc');
}, 1500);
// Stop triggering GC events altogether after 2.5 seconds
setTimeout(() => {
clearInterval(interval);
}, 2500);
v8.stopCoverage()
Метод v8.stopCoverage() позволяет пользователю остановить сбор данных о покрытии, начатый с помощью NODE_V8_COVERAGE, чтобы V8 мог освободить записи счетчиков выполнения и оптимизировать код. Его можно использовать вместе с v8.takeCoverage(), если пользователю требуется собирать данные о покрытии по запросу.
v8.takeCoverage()
Метод v8.takeCoverage() позволяет пользователю записывать на диск по запросу данные о покрытии, сбор которых начат с помощью NODE_V8_COVERAGE. Этот метод можно вызывать несколько раз в течение времени работы процесса. При каждом вызове счетчик выполнения будет сбрасываться, а в каталог, указанный в NODE_V8_COVERAGE, будет записываться новый отчет о покрытии.
Перед завершением процесса на диск будет записан еще один отчет о покрытии, если только перед завершением процесса не был вызван v8.stopCoverage().
v8.writeHeapSnapshot([filename[,options]])
-
filename<string> Путь к файлу, в который следует сохранить снимок кучи V8. Если не указан, будет создано имя файла по шаблону'Heap-${yyyymmdd}-${hhmmss}-${pid}-${thread_id}.heapsnapshot', где{pid}— PID процесса Node.js, а{thread_id}будет равно0, еслиwriteHeapSnapshot()вызывается из основного потока Node.js, либо будет содержать идентификатор рабочего потока. -
options<Object> - Возвращает: <string> Имя файла, в который был сохранен снимок.
Создает снимок текущей кучи V8 и записывает его в файл JSON. Этот файл предназначен для использования с такими инструментами, как Chrome DevTools. Схема JSON не документирована и специфична для движка V8 и может меняться от одной версии V8 к другой.
Снимок кучи относится к одному экземпляру изолята V8. При использовании рабочих потоков снимок кучи, созданный в основном потоке, не будет содержать сведений о рабочих потоках, и наоборот.
Для создания снимка кучи требуется объем памяти, примерно вдвое превышающий размер кучи на момент создания снимка. Это создает риск завершения процесса средствами OOM killer.
Создание снимка — синхронная операция, которая блокирует цикл событий на время, зависящее от размера кучи.
Модули JavaScript
import { writeHeapSnapshot } from 'node:v8';
import { Worker, isMainThread, parentPort } from 'node:worker_threads';
import { fileURLToPath } from 'node:url';
if (isMainThread) {
const __filename = fileURLToPath(import.meta.url);
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());
}
});
}CommonJS
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)
-
limit<integer>
API ничего не делает, если --heapsnapshot-near-heap-limit уже задан в командной строке или если API вызывается более одного раза. limit должно быть положительным целым числом. Подробнее см. в разделе --heapsnapshot-near-heap-limit.
API сериализации
API сериализации предоставляет средства для сериализации значений JavaScript способом, совместимым с алгоритмом структурированного клонирования HTML.
Формат обратно совместим (то есть его безопасно хранить на диске). Одинаковые значения JavaScript могут приводить к разным сериализованным результатам.
v8.serialize(value)
Использует DefaultSerializer для сериализации value в буфер.
ERR_BUFFER_TOO_LARGE будет выброшена при попытке сериализовать огромный объект, для которого требуется буфер размером больше buffer.constants.MAX_LENGTH.
v8.deserialize(buffer)
-
buffer<Buffer> | <TypedArray> | <DataView> Буфер, возвращённый методомserialize().
Использует DefaultDeserializer с параметрами по умолчанию для чтения значения JS из буфера.
Класс: v8.Serializer
new Serializer()
Создаёт новый объект Serializer.
serializer.writeHeader()
Записывает заголовок, содержащий версию формата сериализации.
serializer.writeValue(value)
-
value<any>
Сериализует значение JavaScript и добавляет его сериализованное представление во внутренний буфер.
Если value невозможно сериализовать, будет выброшена ошибка.
serializer.releaseBuffer()
- Возвращает: <Buffer>
Возвращает сохранённый внутренний буфер. После освобождения буфера этот сериализатор использовать нельзя. Вызов этого метода приводит к неопределённому поведению, если предыдущая запись завершилась ошибкой.
serializer.transferArrayBuffer(id, arrayBuffer)
-
id<integer> 32-разрядное беззнаковое целое число. -
arrayBuffer<ArrayBuffer> ЭкземплярArrayBuffer.
Помечает ArrayBuffer как объект, содержимое которого передаётся вне основного потока. Передайте соответствующий ArrayBuffer в контексте десериализации в deserializer.transferArrayBuffer().
serializer.writeUint32(value)
-
value<integer>
Записывает необработанное 32-разрядное беззнаковое целое число. Используется внутри пользовательского serializer._writeHostObject().
serializer.writeUint64(hi, lo)
Записывает необработанное 64-разрядное беззнаковое целое число, разделённое на старшую и младшую 32-разрядные части. Используется внутри пользовательского serializer._writeHostObject().
serializer.writeDouble(value)
-
value<number>
Записывает значение number JS. Используется внутри пользовательского serializer._writeHostObject().
serializer.writeRawBytes(buffer)
-
buffer<Buffer> | <TypedArray> | <DataView>
Записывает необработанные байты во внутренний буфер сериализатора. Десериализатору потребуется способ вычислить длину буфера. Используется внутри пользовательского serializer._writeHostObject().
serializer._writeHostObject(object)
-
object<Object>
Этот метод вызывается для записи некоторого вида хост-объекта, то есть объекта, созданного нативными привязками C++. Если сериализовать object невозможно, следует выбросить подходящее исключение.
Этот метод отсутствует в самом классе Serializer, но может быть реализован в подклассах.
serializer._getDataCloneError(message)
-
message<string>
Этот метод вызывается для создания объектов ошибок, которые будут выброшены, если объект невозможно клонировать.
По умолчанию этот метод использует конструктор Error; его можно переопределить в подклассах.
serializer._getSharedArrayBufferId(sharedArrayBuffer)
-
sharedArrayBuffer<SharedArrayBuffer>
Этот метод вызывается, когда сериализатор собирается сериализовать объект SharedArrayBuffer. Он должен возвращать беззнаковый 32-разрядный идентификатор объекта, используя тот же идентификатор, если этот SharedArrayBuffer уже был сериализован. При десериализации этот идентификатор будет передан в deserializer.transferArrayBuffer().
Если объект невозможно сериализовать, следует выбросить исключение.
Этот метод отсутствует в самом классе Serializer, но может быть реализован в подклассах.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
-
flag<boolean> По умолчанию:false
Указывает, следует ли рассматривать объекты TypedArray и DataView как хост-объекты, то есть передавать их в serializer._writeHostObject().
Класс: v8.Deserializer
new Deserializer(buffer)
-
buffer<Buffer> | <TypedArray> | <DataView> Буфер, возвращённый методомserializer.releaseBuffer().
Создаёт новый объект Deserializer.
deserializer.readHeader()
Читает и проверяет заголовок (включая версию формата). Например, метод может отклонить недопустимый или неподдерживаемый формат передачи данных. В этом случае выбрасывается Error.
deserializer.readValue()
Десериализует значение JavaScript из буфера и возвращает его.
deserializer.transferArrayBuffer(id, arrayBuffer)
-
id<integer> 32-разрядное беззнаковое целое число. -
arrayBuffer<ArrayBuffer> | <SharedArrayBuffer> ЭкземплярArrayBuffer.
Помечает ArrayBuffer как объект, содержимое которого передаётся вне основного потока. Передайте соответствующий ArrayBuffer в контексте сериализации в serializer.transferArrayBuffer() (или верните id из serializer._getSharedArrayBufferId() для SharedArrayBuffer).
deserializer.getWireFormatVersion()
- Возвращает: <integer>
Читает версию используемого формата передачи данных. Вероятно, этот метод будет полезен главным образом для устаревшего кода, читающего старые версии формата. Его нельзя вызывать до .readHeader().
deserializer.readUint32()
- Возвращает: <integer>
Читает необработанное 32-разрядное беззнаковое целое число и возвращает его. Используется внутри пользовательского deserializer._readHostObject().
deserializer.readUint64()
- Возвращает: <integer[]>
Читает необработанное 64-разрядное беззнаковое целое число и возвращает его в виде массива [hi, lo] с двумя элементами — 32-разрядными беззнаковыми целыми числами. Используется внутри пользовательского deserializer._readHostObject().
deserializer.readDouble()
- Возвращает: <number>
Читает значение number JS. Используется внутри пользовательского deserializer._readHostObject().
deserializer.readRawBytes(length)
Читает необработанные байты из внутреннего буфера десериализатора. Параметр length должен соответствовать длине буфера, переданного в serializer.writeRawBytes(). Используется внутри пользовательского deserializer._readHostObject().
deserializer._readHostObject()
Этот метод вызывается для чтения некоторого вида хост-объекта, то есть объекта, созданного нативными привязками C++. Если десериализовать данные невозможно, следует выбросить подходящее исключение.
Этот метод отсутствует в самом классе Deserializer, но может быть реализован в подклассах.
Класс: v8.DefaultSerializer
Подкласс Serializer, который сериализует TypedArray (в частности, Buffer) и объекты DataView как хост-объекты и сохраняет только ту часть их базовых ArrayBuffer, на которую они ссылаются.
Класс: v8.DefaultDeserializer
Подкласс Deserializer, соответствующий формату, записываемому методом DefaultSerializer.
Перехватчики промисов
Интерфейс promiseHooks можно использовать для отслеживания событий жизненного цикла промисов. Для отслеживания всей асинхронной активности см. async_hooks, который внутри использует этот модуль для создания событий жизненного цикла промисов, а также событий для других асинхронных ресурсов. Для управления контекстом запросов см. AsyncLocalStorage.
Модули JavaScript
import { promiseHooks } from 'node:v8';
// There are four lifecycle events produced by promises:
// The `init` event represents the creation of a promise. This could be a
// direct creation such as with `new Promise(...)` or a continuation such
// as `then()` or `catch()`. It also happens whenever an async function is
// called or does an `await`. If a continuation promise is created, the
// `parent` will be the promise it is a continuation from.
function init(promise, parent) {
console.log('a promise was created', { promise, parent });
}
// The `settled` event happens when a promise receives a resolution or
// rejection value. This may happen synchronously such as when using
// `Promise.resolve()` on non-promise input.
function settled(promise) {
console.log('a promise resolved or rejected', { promise });
}
// The `before` event runs immediately before a `then()` or `catch()` handler
// runs or an `await` resumes execution.
function before(promise) {
console.log('a promise is about to call a then handler', { promise });
}
// The `after` event runs immediately after a `then()` handler runs or when
// an `await` begins after resuming from another.
function after(promise) {
console.log('a promise is done calling a then handler', { promise });
}
// Lifecycle hooks may be started and stopped individually
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);
// Or they may be started and stopped in groups
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
});
// Trigger the hooks by using promises
const promiseLog = (word) => Promise.resolve(word).then(console.log);
promiseLog('Hello');
promiseLog('World');
// To stop a hook, call the function returned at its creation.
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet();CommonJS
const { promiseHooks } = require('node:v8');
// There are four lifecycle events produced by promises:
// The `init` event represents the creation of a promise. This could be a
// direct creation such as with `new Promise(...)` or a continuation such
// as `then()` or `catch()`. It also happens whenever an async function is
// called or does an `await`. If a continuation promise is created, the
// `parent` will be the promise it is a continuation from.
function init(promise, parent) {
console.log('a promise was created', { promise, parent });
}
// The `settled` event happens when a promise receives a resolution or
// rejection value. This may happen synchronously such as when using
// `Promise.resolve()` on non-promise input.
function settled(promise) {
console.log('a promise resolved or rejected', { promise });
}
// The `before` event runs immediately before a `then()` or `catch()` handler
// runs or an `await` resumes execution.
function before(promise) {
console.log('a promise is about to call a then handler', { promise });
}
// The `after` event runs immediately after a `then()` handler runs or when
// an `await` begins after resuming from another.
function after(promise) {
console.log('a promise is done calling a then handler', { promise });
}
// Lifecycle hooks may be started and stopped individually
const stopWatchingInits = promiseHooks.onInit(init);
const stopWatchingSettleds = promiseHooks.onSettled(settled);
const stopWatchingBefores = promiseHooks.onBefore(before);
const stopWatchingAfters = promiseHooks.onAfter(after);
// Or they may be started and stopped in groups
const stopHookSet = promiseHooks.createHook({
init,
settled,
before,
after,
});
// Trigger the hooks by using promises
const promisePrint = (word) => Promise.resolve(word).then(console.log);
promisePrint('Hello');
promisePrint('World');
// To stop a hook, call the function returned at its creation.
stopWatchingInits();
stopWatchingSettleds();
stopWatchingBefores();
stopWatchingAfters();
stopHookSet();
promiseHooks.onInit(init)
-
init<Function> Функция обратного вызоваinit, вызываемая при создании промиса. - Возвращает: <Function> Вызовите, чтобы остановить перехватчик.
Перехватчик init должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она вызовет бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onInit((promise, parent) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onInit((promise, parent) => {});
promiseHooks.onSettled(settled)
-
settled<Function> Функция обратного вызоваsettled, вызываемая при выполнении промиса или отклонении его выполнения. - Возвращает: <Function> Вызовите, чтобы остановить перехватчик.
Перехватчик settled должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она вызовет бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onSettled((promise) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onSettled((promise) => {});
promiseHooks.onBefore(before)
-
before<Function> Функция обратного вызоваbefore, вызываемая перед выполнением продолжения промиса. - Возвращает: <Function> Вызовите, чтобы остановить перехватчик.
Перехватчик before должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она вызовет бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onBefore((promise) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onBefore((promise) => {});
promiseHooks.onAfter(after)
-
after<Function> Функция обратного вызоваafter, вызываемая после выполнения продолжения промиса. - Возвращает: <Function> Вызовите, чтобы остановить перехватчик.
Перехватчик after должен быть обычной функцией. Передача асинхронной функции приведёт к ошибке, поскольку она вызовет бесконечный цикл микрозадач.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stop = promiseHooks.onAfter((promise) => {});CommonJS
const { promiseHooks } = require('node:v8');
const stop = promiseHooks.onAfter((promise) => {});
promiseHooks.createHook(callbacks)
-
callbacks<Object> Функции обратного вызова перехватчиков, которые нужно зарегистрировать (Hook Callbacks)-
init<Function> Функция обратного вызоваinit. -
before<Function> Функция обратного вызоваbefore. -
after<Function> Функция обратного вызоваafter. -
settled<Function> Функция обратного вызоваsettled.
-
- Возвращает: <Function> Используется для отключения перехватчиков
Функции обратного вызова перехватчиков должны быть обычными функциями. Передача асинхронных функций приведёт к ошибке, поскольку они вызовут бесконечный цикл микрозадач.
Регистрирует функции, вызываемые при различных событиях жизненного цикла каждого промиса.
Функции обратного вызова init()/before()/after()/settled() вызываются при соответствующих событиях в течение жизненного цикла промиса.
Все функции обратного вызова необязательны. Например, если требуется отслеживать только создание промиса, достаточно передать функцию обратного вызова init. Подробные сведения обо всех функциях, которые можно передать в callbacks, приведены в разделе Функции обратного вызова перехватчиков.
Модули JavaScript
import { promiseHooks } from 'node:v8';
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
});CommonJS
const { promiseHooks } = require('node:v8');
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
});Функции обратного вызова перехватчиков
Ключевые события жизненного цикла промиса разделены на четыре категории: создание промиса, выполнение обработчика продолжения (до и после вызова) или выполнение кода вокруг await, а также разрешение или отклонение промиса.
Эти перехватчики похожи на перехватчики async_hooks, но у них отсутствует перехватчик destroy. Другие типы асинхронных ресурсов обычно представляют собой сокеты или файловые дескрипторы, имеющие отдельное состояние «закрыт», которое обозначает событие жизненного цикла destroy; промисы же остаются пригодными для использования, пока код может к ним обращаться. Чтобы вписать промисы в модель событий async_hooks, отслеживается сборка мусора, однако такое отслеживание очень затратное, и сборка мусора для них может вообще никогда не выполняться.
Поскольку промисы являются асинхронными ресурсами, жизненный цикл которых отслеживается механизмом перехватчиков промисов, функции обратного вызова init(), before(), after() и settled() не должны быть асинхронными функциями, поскольку они создают новые промисы, что привело бы к бесконечному циклу.
Хотя этот API используется для передачи событий промисов в async_hooks, порядок событий между двумя API не определён. Оба API являются многопользовательскими, поэтому события одного API могут происходить в любом порядке относительно событий другого.
init(promise, parent)
-
promise<Promise> Создаваемый промис. -
parent<Promise> Промис, продолжением которого является создаваемый промис, если применимо.
Вызывается при создании промиса. Это не означает, что произойдут соответствующие события before/after, а лишь указывает на такую возможность. Это происходит, если промис создан, но для него так и не было создано продолжение.
before(promise)
-
promise<Promise>
Вызывается перед выполнением продолжения промиса. Это может быть обработчик then(), catch() или finally(), а также возобновление await.
Функция обратного вызова before будет вызвана от 0 до N раз. Функция обратного вызова before обычно не вызывается, если для промиса не было создано продолжение. Функция обратного вызова before может вызываться много раз, если для одного промиса создано несколько продолжений.
after(promise)
-
promise<Promise>
Вызывается сразу после выполнения продолжения промиса. Это может произойти после обработчика then(), catch() или finally() либо перед await после другого await.
settled(promise)
-
promise<Promise>
Вызывается, когда промис получает значение разрешения или отклонения. Это может произойти синхронно в случае Promise.resolve() или Promise.reject().
API снимков при запуске
Интерфейс v8.startupSnapshot можно использовать для добавления хуков сериализации и десериализации пользовательских снимков при запуске.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js # This launches a process with the snapshot $ node --snapshot-blob snapshot.blob copy
В приведённом выше примере entry.js может использовать методы интерфейса v8.startupSnapshot, чтобы указать, как сохранять сведения о пользовательских объектах в снимке при сериализации и как использовать эти сведения для синхронизации объектов при десериализации снимка. Например, если entry.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();
// Reading a series of files from directory and store them into 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 here is where the snapshot script is placed
// during snapshot building time.
const shelf = new BookShelf(__dirname, [
'book1.en_US.txt',
'book1.es_ES.txt',
'book2.zh_CN.txt',
]);
assert(v8.startupSnapshot.isBuildingSnapshot());
// On snapshot serialization, compress the books to reduce size.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf);
// On snapshot deserialization, decompress the books.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf);
v8.startupSnapshot.setDeserializeMainFunction((shelf) => {
// process.env and process.argv are refreshed during snapshot
// deserialization.
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); copy При запуске полученный бинарный файл напечатает данные, десериализованные из снимка, используя обновлённые process.env и process.argv запущенного процесса:
$ BOOK_LANG=es_ES node --snapshot-blob snapshot.blob book1 # Prints content of book1.es_ES.txt deserialized from the snapshot. copy
В настоящее время приложение, десериализованное из пользовательского снимка, нельзя снова сохранить в виде снимка, поэтому эти API доступны только приложениям, которые не были десериализованы из пользовательского снимка.
v8.startupSnapshot.addSerializeCallback(callback[, data])
-
callback<Function> Функция обратного вызова, вызываемая перед сериализацией. -
data<any> Необязательные данные, которые будут переданы вcallbackпри её вызове.
Добавляет функцию обратного вызова, которая будет вызвана перед сериализацией экземпляра Node.js в снимок и завершением работы. Её можно использовать для освобождения ресурсов, которые не следует или невозможно сериализовать, либо для преобразования пользовательских данных в более подходящий для сериализации формат.
Функции обратного вызова выполняются в порядке добавления.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
-
callback<Function> Функция обратного вызова, вызываемая после десериализации снимка. -
data<any> Необязательные данные, которые будут переданы вcallbackпри её вызове.
Добавляет функцию обратного вызова, которая будет вызвана при десериализации экземпляра Node.js из снимка. callback и data (если указаны) будут сериализованы в снимок; их можно использовать для повторной инициализации состояния приложения или повторного получения ресурсов, необходимых приложению при его перезапуске из снимка.
Функции обратного вызова выполняются в порядке добавления.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
-
callback<Function> Функция обратного вызова, вызываемая в качестве точки входа после десериализации снимка. -
data<any> Необязательные данные, которые будут переданы вcallbackпри её вызове.
Задаёт точку входа приложения Node.js при его десериализации из снимка. Этот метод можно вызвать только один раз в скрипте создания снимка. Если он вызван, десериализованному приложению больше не требуется дополнительный скрипт точки входа для запуска: будет просто вызвана функция обратного вызова с десериализованными данными (если они предоставлены). В противном случае для десериализованного приложения по-прежнему потребуется скрипт точки входа.
v8.startupSnapshot.isBuildingSnapshot()
- Возвращает: <boolean>
Возвращает true, если экземпляр Node.js запущен для создания снимка.
Класс: v8.GCProfiler
Этот API собирает данные о сборке мусора в текущем потоке.
new v8.GCProfiler()
Создаёт новый экземпляр класса v8.GCProfiler. Этот API поддерживает синтаксис using.
profiler.start()
Начинает сбор данных о сборке мусора.
profiler.stop()
Останавливает сбор данных о сборке мусора и возвращает объект. Объект содержит следующие данные.
{
"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
} copy Пример:
Модули JavaScript
import { GCProfiler } from 'node:v8';
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
console.log(profiler.stop());
}, 1000);CommonJS
const { GCProfiler } = require('node:v8');
const profiler = new GCProfiler();
profiler.start();
setTimeout(() => {
console.log(profiler.stop());
}, 1000);
profiler[Symbol.dispose]()
Останавливает сбор данных о сборке мусора и удаляет профиль.
Class: SyncCPUProfileHandle
syncCpuProfileHandle.stop()
- Возвращает: <string>
Останавливает сбор профиля и возвращает данные профиля.
syncCpuProfileHandle[Symbol.dispose]()
Останавливает сбор профиля и отбрасывает профиль.
Class: CPUProfileHandle
cpuProfileHandle.stop()
- Возвращает: <Promise>
Останавливает сбор профиля, а затем возвращает Promise, который разрешается с ошибкой или данными профиля.
cpuProfileHandle[Symbol.asyncDispose]()
- Возвращает: <Promise>
Останавливает сбор профиля и отбрасывает профиль.
Class: HeapProfileHandle
heapProfileHandle.stop()
- Возвращает: <Promise>
Останавливает сбор профиля, а затем возвращает Promise, который разрешается с ошибкой или данными профиля.
heapProfileHandle[Symbol.asyncDispose]()
- Возвращает: <Promise>
Останавливает сбор профиля и отбрасывает профиль.
v8.isStringOneByteRepresentation(content)
V8 поддерживает только Latin-1/ISO-8859-1 и UTF16 в качестве внутреннего представления строки. Если для content используется Latin-1/ISO-8859-1 в качестве внутреннего представления, эта функция возвращает true; в противном случае она возвращает false.
Если этот метод возвращает false, это не означает, что строка содержит символы, отсутствующие в Latin-1/ISO-8859-1. Иногда строка Latin-1 также может быть представлена как UTF16.
Модули JavaScript
import { isStringOneByteRepresentation } from 'node:v8';
import { Buffer } from 'node:buffer';
const Encoding = {
latin1: 1,
utf16le: 2,
};
const buffer = Buffer.alloc(100);
function writeString(input) {
if (isStringOneByteRepresentation(input)) {
console.log(`input: '${input}'`);
buffer.writeUint8(Encoding.latin1);
buffer.writeUint32LE(input.length, 1);
buffer.write(input, 5, 'latin1');
console.log(`decoded: '${buffer.toString('latin1', 5, 5 + input.length)}'\n`);
} else {
console.log(`input: '${input}'`);
buffer.writeUint8(Encoding.utf16le);
buffer.writeUint32LE(input.length * 2, 1);
buffer.write(input, 5, 'utf16le');
console.log(`decoded: '${buffer.toString('utf16le', 5, 5 + input.length * 2)}'`);
}
}
writeString('hello');
writeString('你好');CommonJS
const { isStringOneByteRepresentation } = require('node:v8');
const { Buffer } = require('node:buffer');
const Encoding = {
latin1: 1,
utf16le: 2,
};
const buffer = Buffer.alloc(100);
function writeString(input) {
if (isStringOneByteRepresentation(input)) {
console.log(`input: '${input}'`);
buffer.writeUint8(Encoding.latin1);
buffer.writeUint32LE(input.length, 1);
buffer.write(input, 5, 'latin1');
console.log(`decoded: '${buffer.toString('latin1', 5, 5 + input.length)}'\n`);
} else {
console.log(`input: '${input}'`);
buffer.writeUint8(Encoding.utf16le);
buffer.writeUint32LE(input.length * 2, 1);
buffer.write(input, 5, 'utf16le');
console.log(`decoded: '${buffer.toString('utf16le', 5, 5 + input.length * 2)}'`);
}
}
writeString('hello');
writeString('你好');
v8.startCpuProfile()
- Возвращает: <SyncCPUProfileHandle>
Запускает профилирование ЦП, а затем возвращает объект SyncCPUProfileHandle. Этот API поддерживает синтаксис using.
const handle = v8.startCpuProfile(); const profile = handle.stop(); console.log(profile); copy
© Joyent, Inc. and other Node contributors
Licensed under the MIT License.
Node.js is a trademark of Joyent, Inc. and is used with its permission.
We are not endorsed by or affiliated with Joyent.
https://nodejs.org/dist/latest-v24.x/docs/api/v8.html