V8
소스 코드: lib/v8.js
node:v8
모듈은 Node.js 바이너리에 내장된 V8 버전에 특정한 API를 노출합니다. 다음을 사용하여 접근할 수 있습니다:
const v8 = require('node:v8')
v8.cachedDataVersionTag()
추가된 버전: v8.0.0
- 반환 값: <integer>
V8 버전, 커맨드라인 플래그, 감지된 CPU 기능에서 파생된 버전 태그를 나타내는 정수를 반환합니다. 이것은 vm.Script
cachedData
버퍼가 이 V8 인스턴스와 호환되는지 여부를 결정하는 데 유용합니다.
console.log(v8.cachedDataVersionTag()) // 3947234607
// v8.cachedDataVersionTag()에서 반환된 값은 V8 버전, 커맨드라인 플래그 및
// 감지된 CPU 기능에서 파생됩니다. 플래그가 토글될 때 값이 실제로 업데이트되는지 테스트합니다.
v8.setFlagsFromString('--allow_natives_syntax')
console.log(v8.cachedDataVersionTag()) // 183726201
v8.getHeapCodeStatistics()
추가된 버전: v12.8.0
- 반환 값: <Object>
힙의 코드와 해당 메타데이터에 대한 통계를 가져옵니다. V8 GetHeapCodeAndMetadataStatistics
API를 참조하십시오. 다음 속성을 가진 객체를 반환합니다:
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,
}
v8.getHeapSnapshot([options])
[연혁]
버전 | 변경 사항 |
---|---|
v19.1.0 | 힙 스냅샷을 구성하는 옵션 지원. |
v11.13.0 | 추가됨: v11.13.0 |
options
<Object>반환값: <stream.Readable> V8 힙 스냅샷을 포함하는 읽기 가능한 스트림.
현재 V8 힙의 스냅샷을 생성하고 JSON 직렬화된 표현을 읽는 데 사용할 수 있는 읽기 가능한 스트림을 반환합니다. 이 JSON 스트림 형식은 Chrome DevTools와 같은 도구와 함께 사용하도록 고안되었습니다. JSON 스키마는 문서화되지 않았으며 V8 엔진에 특화되어 있습니다. 따라서 스키마는 V8 버전이 바뀔 때마다 변경될 수 있습니다.
힙 스냅샷을 생성하려면 스냅샷이 생성될 때 힙 크기의 약 두 배의 메모리가 필요합니다. 이로 인해 OOM 킬러가 프로세스를 종료할 위험이 있습니다.
스냅샷 생성은 동기식 작업이며 힙 크기에 따라 이벤트 루프를 차단합니다.
// 콘솔에 힙 스냅샷 출력
const v8 = require('node:v8')
const stream = v8.getHeapSnapshot()
stream.pipe(process.stdout)
v8.getHeapSpaceStatistics()
[연혁]
버전 | 변경 사항 |
---|---|
v7.5.0 | 32비트 부호 없는 정수 범위를 초과하는 값 지원. |
v6.0.0 | 추가됨: v6.0.0 |
- 반환값: <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
}
]
v8.getHeapStatistics()
[기록]
버전 | 변경 사항 |
---|---|
v7.5.0 | 32비트 부호 없는 정수 범위를 초과하는 값 지원. |
v7.2.0 | malloced_memory , peak_malloced_memory , 및 does_zap_garbage 추가. |
v1.0.0 | v1.0.0에 추가됨 |
- 반환값: <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의 값은 현재 V8의 JavaScript 객체에서 사용 중인 바이트 수입니다. 이는 실제로 사용 중인 메모리이며 할당되었지만 아직 사용되지 않은 메모리는 포함하지 않습니다.
heap_size_limit
heap_size_limit 값은 V8 힙의 최대 크기이며, 바이트 단위입니다(시스템 리소스에 의해 결정되는 기본 제한 또는 --max_old_space_size
옵션에 전달된 값).
malloced_memory
malloced_memory의 값은 V8에 의해 malloc
을 통해 할당된 바이트 수입니다.
peak_malloced_memory
peak_malloced_memory의 값은 프로세스 수명 동안 V8에 의해 malloc
을 통해 할당된 최대 바이트 수입니다.
does_zap_garbage
는 --zap_code_space
옵션이 활성화되었는지 여부를 나타내는 0/1 부울입니다. 이를 통해 V8은 힙 가비지를 비트 패턴으로 덮어씁니다. RSS 풋프린트(상주 집합 크기)는 모든 힙 페이지를 계속해서 터치하기 때문에 더 커지며, 운영 체제에서 스왑 아웃될 가능성이 줄어듭니다.
number_of_native_contexts
native_context의 값은 현재 활성 상태인 최상위 컨텍스트의 수입니다. 시간이 지남에 따라 이 숫자가 증가하면 메모리 누수를 나타냅니다.
number_of_detached_contexts
detached_context의 값은 분리되었지만 아직 가비지 수집되지 않은 컨텍스트의 수입니다. 이 숫자가 0이 아니면 잠재적인 메모리 누수를 나타냅니다.
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
}
v8.queryObjects(ctor[, options])
추가된 버전: v22.0.0, v20.13.0
ctor
<Function> 힙에서 대상 객체를 필터링하기 위해 프로토타입 체인에서 검색하는 데 사용할 수 있는 생성자입니다.options
<undefined> | <Object>format
<string>'count'
이면 일치하는 객체의 수가 반환됩니다.'summary'
이면 일치하는 객체의 요약 문자열이 있는 배열이 반환됩니다.
반환값: {number|Array
이것은 Chromium DevTools 콘솔에서 제공하는 queryObjects()
콘솔 API와 유사합니다. 전체 가비지 컬렉션 후 힙에서 프로토타입 체인에 일치하는 생성자를 가진 객체를 검색하는 데 사용할 수 있으며, 이는 메모리 누수 회귀 테스트에 유용할 수 있습니다. 놀라운 결과를 피하기 위해 사용자는 자신이 제어하지 않는 구현을 가진 생성자 또는 응용 프로그램의 다른 당사자가 호출할 수 있는 생성자에서 이 API를 사용하지 않아야 합니다.
우발적인 누출을 방지하기 위해 이 API는 발견된 객체에 대한 원시 참조를 반환하지 않습니다. 기본적으로 발견된 객체의 수를 반환합니다. options.format
이 'summary'
이면 각 객체에 대한 간략한 문자열 표현이 포함된 배열을 반환합니다. 이 API에서 제공되는 가시성은 힙 스냅샷이 제공하는 것과 유사하지만 사용자는 직렬화 및 구문 분석 비용을 절약하고 검색 중에 대상 객체를 직접 필터링할 수 있습니다.
현재 실행 컨텍스트에서 생성된 객체만 결과에 포함됩니다.
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' }))
// 생성자에서 상속된 자식 클래스가 있는 경우,
// 생성자는 자식 클래스의 프로토타입 체인에도 표시되므로
// 자식 클래스의 프로토타입도 결과에 포함됩니다.
console.log(queryObjects(A)) // 3
// [ "B { foo: 'bar', bar: 'qux' }", 'A {}', "A { foo: 'bar' }" ]
console.log(queryObjects(A, { format: 'summary' }))
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' }))
// 생성자에서 상속된 자식 클래스가 있는 경우,
// 생성자는 자식 클래스의 프로토타입 체인에도 표시되므로
// 자식 클래스의 프로토타입도 결과에 포함됩니다.
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
flags
<string>
v8.setFlagsFromString()
메서드는 V8 명령줄 플래그를 프로그래밍 방식으로 설정하는 데 사용할 수 있습니다. 이 메서드는 주의해서 사용해야 합니다. VM이 시작된 후 설정을 변경하면 충돌 및 데이터 손실을 포함한 예측할 수 없는 동작이 발생하거나 아무 동작도 하지 않을 수 있습니다.
Node.js 버전에 사용할 수 있는 V8 옵션은 node --v8-options
를 실행하여 확인할 수 있습니다.
사용법:
// 1분 동안 GC 이벤트를 stdout에 출력합니다.
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>반환 값: <string> 스냅샷이 저장된 파일 이름입니다.
현재 V8 힙의 스냅샷을 생성하고 JSON 파일에 씁니다. 이 파일은 Chrome DevTools와 같은 도구와 함께 사용하기 위한 것입니다. JSON 스키마는 문서화되지 않았으며 V8 엔진에 특정하며 V8 버전마다 변경될 수 있습니다.
힙 스냅샷은 단일 V8 격리에 특화되어 있습니다. 워커 스레드를 사용하는 경우 메인 스레드에서 생성된 힙 스냅샷에는 워커에 대한 정보가 포함되지 않으며, 반대의 경우도 마찬가지입니다.
힙 스냅샷을 만들려면 스냅샷 생성 당시의 힙 크기의 약 두 배의 메모리가 필요합니다. 이로 인해 OOM 킬러가 프로세스를 종료할 위험이 있습니다.
스냅샷 생성은 힙 크기에 따라 이벤트 루프를 차단하는 동기 작업입니다.
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(`워커 힙덤프: ${filename}`)
// 이제 메인 스레드의 힙덤프를 가져옵니다.
console.log(`메인 스레드 힙덤프: ${writeHeapSnapshot()}`)
})
// 워커에게 힙덤프를 생성하도록 지시합니다.
worker.postMessage('heapdump')
} else {
parentPort.once('message', message => {
if (message === 'heapdump') {
// 워커에 대한 힙덤프를 생성합니다.
// 부모에게 파일 이름을 반환합니다.
parentPort.postMessage(writeHeapSnapshot())
}
})
}
v8.setHeapSnapshotNearHeapLimit(limit)
추가된 버전: v18.10.0, v16.18.0
limit
<integer>
--heapsnapshot-near-heap-limit
가 이미 명령줄에서 설정되었거나 API가 두 번 이상 호출된 경우에는 API가 아무 작업도 수행하지 않습니다. limit
는 양의 정수여야 합니다. 자세한 내용은 --heapsnapshot-near-heap-limit
를 참조하십시오.
직렬화 API
직렬화 API는 HTML 구조적 복제 알고리즘과 호환되는 방식으로 JavaScript 값을 직렬화하는 방법을 제공합니다.
형식은 하위 호환 가능합니다(즉, 디스크에 저장해도 안전). 동일한 JavaScript 값이라도 다른 직렬화 출력이 생성될 수 있습니다.
v8.serialize(value)
추가된 버전: v8.0.0
DefaultSerializer
를 사용하여 value
를 버퍼로 직렬화합니다.
ERR_BUFFER_TOO_LARGE
는 buffer.constants.MAX_LENGTH
보다 큰 버퍼를 필요로 하는 거대한 객체를 직렬화하려고 할 때 발생합니다.
v8.deserialize(buffer)
추가된 버전: v8.0.0
buffer
<Buffer> | <TypedArray> | <DataView>serialize()
에서 반환된 버퍼입니다.
기본 옵션과 함께 DefaultDeserializer
를 사용하여 버퍼에서 JS 값을 읽습니다.
클래스: v8.Serializer
추가된 버전: v8.0.0
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>
JS number
값을 씁니다. 사용자 정의 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
객체를 직렬화하려고 할 때 호출됩니다. 이 SharedArrayBuffer
가 이미 직렬화된 경우 동일한 ID를 사용하여 객체에 대한 부호 없는 32비트 정수 ID를 반환해야 합니다. 역직렬화할 때 이 ID는 deserializer.transferArrayBuffer()
로 전달됩니다.
객체를 직렬화할 수 없는 경우 예외를 발생시켜야 합니다.
이 메서드는 Serializer
클래스 자체에는 존재하지 않지만 서브클래스에서 제공할 수 있습니다.
serializer._setTreatArrayBufferViewsAsHostObjects(flag)
flag
<boolean> 기본값:false
TypedArray
및 DataView
객체를 호스트 객체로 처리할지 여부를 나타냅니다. 즉, serializer._writeHostObject()
로 전달합니다.
클래스: v8.Deserializer
v8.0.0에 추가됨
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()
로 전달합니다(또는 SharedArrayBuffer
의 경우 serializer._getSharedArrayBufferId()
에서 id
를 반환합니다).
deserializer.getWireFormatVersion()
- 반환값: <integer>
기본 와이어 형식 버전을 읽습니다. 주로 이전 와이어 형식 버전을 읽는 레거시 코드에 유용할 수 있습니다. .readHeader()
전에 호출하면 안 됩니다.
deserializer.readUint32()
- 반환값: <integer>
원시 32비트 부호 없는 정수를 읽고 반환합니다. 사용자 지정 deserializer._readHostObject()
내부에서 사용됩니다.
deserializer.readUint64()
- 반환값: <integer[]>
원시 64비트 부호 없는 정수를 읽고 두 개의 32비트 부호 없는 정수 항목이 있는 배열 [hi, lo]
로 반환합니다. 사용자 지정 deserializer._readHostObject()
내부에서 사용됩니다.
deserializer.readDouble()
- 반환값: <number>
JS number
값을 읽습니다. 사용자 지정 deserializer._readHostObject()
내부에서 사용됩니다.
deserializer.readRawBytes(length)
deserializer의 내부 버퍼에서 원시 바이트를 읽습니다. 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 수명 주기 이벤트를 추적하는 데 사용할 수 있습니다. 모든 비동기 활동을 추적하려면 다른 비동기 리소스에 대한 이벤트 외에도 promise 수명 주기 이벤트를 생성하기 위해 내부적으로 이 모듈을 사용하는 async_hooks
를 참조하십시오. 요청 컨텍스트 관리에 대해서는 AsyncLocalStorage
를 참조하십시오.
import { promiseHooks } from 'node:v8'
// 프로미스에서 생성되는 수명 주기 이벤트는 네 가지입니다.
// `init` 이벤트는 프로미스 생성을 나타냅니다. 이는 `new Promise(...)`를 사용한 직접적인 생성일 수도 있고,
// `then()` 또는 `catch()`와 같은 연속일 수도 있습니다. 또한 비동기 함수가 호출되거나 `await`를 수행할 때마다 발생합니다.
// 연속 프로미스가 생성되면 `parent`는 연속 대상이 되는 프로미스가 됩니다.
function init(promise, parent) {
console.log('프로미스가 생성되었습니다.', { promise, parent })
}
// `settled` 이벤트는 프로미스가 해결 또는 거부 값을 받을 때 발생합니다.
// 이는 프로미스가 아닌 입력에 `Promise.resolve()`를 사용할 때처럼 동기적으로 발생할 수 있습니다.
function settled(promise) {
console.log('프로미스가 해결되거나 거부되었습니다.', { promise })
}
// `before` 이벤트는 `then()` 또는 `catch()` 핸들러가 실행되기 직전 또는
// `await`가 실행을 재개하기 직전에 실행됩니다.
function before(promise) {
console.log('프로미스가 then 핸들러를 호출하려고 합니다.', { promise })
}
// `after` 이벤트는 `then()` 핸들러가 실행된 직후 또는
// 다른 핸들러에서 재개한 후 `await`가 시작될 때 실행됩니다.
function after(promise) {
console.log('프로미스가 then 핸들러 호출을 완료했습니다.', { 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
후크는 일반 함수여야 합니다. 비동기 함수를 제공하면 무한 마이크로태스크 루프를 생성하므로 오류가 발생합니다.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onInit((promise, parent) => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onInit((promise, parent) => {})
promiseHooks.onSettled(settled)
추가된 버전: v17.1.0, v16.14.0
settled
<함수> 프로미스가 이행되거나 거부될 때 호출할settled
콜백입니다.- 반환 값: <함수> 후크를 중지하는 호출입니다.
settled
후크는 일반 함수여야 합니다. 비동기 함수를 제공하면 무한 마이크로태스크 루프를 생성하므로 오류가 발생합니다.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onSettled(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onSettled(promise => {})
promiseHooks.onBefore(before)
추가된 버전: v17.1.0, v16.14.0
before
후크는 일반 함수여야 합니다. 비동기 함수를 제공하면 무한 마이크로태스크 루프를 생성하므로 오류가 발생합니다.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onBefore(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onBefore(promise => {})
promiseHooks.onAfter(after)
추가된 버전: v17.1.0, v16.14.0
after
<Function> 약속 연속 실행 후 호출할after
콜백.- 반환 값: <Function> 후크를 중지하기 위한 호출입니다.
after
후크는 일반 함수여야 합니다. 비동기 함수를 제공하면 무한 마이크로태스크 루프가 생성되므로 오류가 발생합니다.
import { promiseHooks } from 'node:v8'
const stop = promiseHooks.onAfter(promise => {})
const { promiseHooks } = require('node:v8')
const stop = promiseHooks.onAfter(promise => {})
promiseHooks.createHook(callbacks)
추가된 버전: v17.1.0, v16.14.0
init
<Function>init
콜백.before
<Function>before
콜백.after
<Function>after
콜백.settled
<Function>settled
콜백.
반환 값: <Function> 후크 비활성화에 사용됩니다.
후크 콜백은 일반 함수여야 합니다. 비동기 함수를 제공하면 무한 마이크로태스크 루프가 생성되므로 오류가 발생합니다.
각 약속의 수명 주기 이벤트에 대해 호출할 함수를 등록합니다.
콜백 init()
/before()
/after()
/settled()
는 약속 수명 동안 각각의 이벤트에 대해 호출됩니다.
모든 콜백은 선택 사항입니다. 예를 들어, 약속 생성만 추적해야 하는 경우 init
콜백만 전달하면 됩니다. callbacks
에 전달할 수 있는 모든 함수의 세부 사항은 후크 콜백 섹션에 있습니다.
import { promiseHooks } from 'node:v8'
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
})
const { promiseHooks } = require('node:v8')
const stopAll = promiseHooks.createHook({
init(promise, parent) {},
})
Hook 콜백
Promise의 수명 주기에서 중요한 이벤트는 Promise 생성, 연속 처리기 호출 전/후 또는 await 주변, Promise가 이행 또는 거부될 때의 네 가지 영역으로 분류됩니다.
이러한 후크는 async_hooks
와 유사하지만 destroy
후크가 없습니다. 다른 유형의 비동기 리소스는 일반적으로 소켓 또는 파일 설명자를 나타내며, "닫힘" 상태가 명확하여 Promise는 코드가 여전히 접근할 수 있는 한 계속 사용할 수 있지만 destroy
수명 주기 이벤트를 나타냅니다. 가비지 컬렉션 추적은 Promise를 async_hooks
이벤트 모델에 맞추기 위해 사용되지만 이 추적은 매우 비용이 많이 들고 가비지 컬렉션이 되지 않을 수도 있습니다.
Promise는 Promise 후크 메커니즘을 통해 수명 주기가 추적되는 비동기 리소스이므로 init()
, before()
, after()
, settled()
콜백은 더 많은 Promise를 생성하여 무한 루프를 생성하므로 비동기 함수가 되어서는 안 됩니다.
이 API는 Promise 이벤트를 async_hooks
에 공급하는 데 사용되지만 둘 사이의 순서는 정의되지 않습니다. 두 API 모두 멀티 테넌트이므로 서로에 대해 임의의 순서로 이벤트를 생성할 수 있습니다.
init(promise, parent)
Promise가 생성될 때 호출됩니다. 이는 해당 before
/after
이벤트가 발생한다는 의미가 아니라 가능성만 존재한다는 의미입니다. 이는 연속이 전혀 이루어지지 않고 Promise가 생성된 경우에 발생합니다.
before(promise)
promise
<Promise>
Promise 연속이 실행되기 전에 호출됩니다. 이는 then()
, catch()
, finally()
처리기 또는 await
재개 형태일 수 있습니다.
before
콜백은 0에서 N번 호출됩니다. 일반적으로 Promise에 대한 연속이 전혀 이루어지지 않은 경우 before
콜백은 0번 호출됩니다. 동일한 Promise에서 많은 연속이 이루어진 경우 before
콜백은 여러 번 호출될 수 있습니다.
after(promise)
promise
<Promise>
promise 연속 실행 직후에 즉시 호출됩니다. 이는 then()
, catch()
, 또는 finally()
핸들러 이후 또는 다른 await
이후의 await
전에 발생할 수 있습니다.
settled(promise)
promise
<Promise>
promise가 해결 또는 거부 값을 받을 때 호출됩니다. 이는 Promise.resolve()
또는 Promise.reject()
의 경우 동기적으로 발생할 수 있습니다.
Startup Snapshot API
추가됨: v18.6.0, v16.17.0
v8.startupSnapshot
인터페이스는 사용자 정의 시작 스냅샷을 위한 직렬화 및 역직렬화 후크를 추가하는 데 사용할 수 있습니다.
$ node --snapshot-blob snapshot.blob --build-snapshot entry.js
# 스냅샷으로 프로세스를 시작합니다. {#this-launches-a-process-with-the-snapshot}
$ node --snapshot-blob snapshot.blob
위의 예에서 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()
// 디렉토리에서 일련의 파일을 읽고 스토리지에 저장합니다.
constructor(directory, books) {
for (const book of books) {
this.storage.set(book, fs.readFileSync(path.join(directory, book)))
}
}
static compressAll(shelf) {
for (const [book, content] of shelf.storage) {
shelf.storage.set(book, zlib.gzipSync(content))
}
}
static decompressAll(shelf) {
for (const [book, content] of shelf.storage) {
shelf.storage.set(book, zlib.gunzipSync(content))
}
}
}
// 여기의 __dirname은 스냅샷 빌드 시간 동안 스냅샷 스크립트가 배치되는 위치입니다.
const shelf = new BookShelf(__dirname, ['book1.en_US.txt', 'book1.es_ES.txt', 'book2.zh_CN.txt'])
assert(v8.startupSnapshot.isBuildingSnapshot())
// 스냅샷 직렬화 시 크기를 줄이기 위해 책을 압축합니다.
v8.startupSnapshot.addSerializeCallback(BookShelf.compressAll, shelf)
// 스냅샷 역직렬화 시 책을 압축 해제합니다.
v8.startupSnapshot.addDeserializeCallback(BookShelf.decompressAll, shelf)
v8.startupSnapshot.setDeserializeMainFunction(shelf => {
// process.env 및 process.argv는 스냅샷 역직렬화 중에 새로 고쳐집니다.
const lang = process.env.BOOK_LANG || 'en_US'
const book = process.argv[1]
const name = `${book}.${lang}.txt`
console.log(shelf.storage.get(name))
}, shelf)
결과 바이너리는 시작 중에 스냅샷에서 역직렬화된 데이터를 출력하고 시작된 프로세스의 새로 고쳐진 process.env
및 process.argv
를 사용합니다.
$ 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
Node.js 인스턴스가 스냅샷으로 직렬화되어 종료되기 직전에 호출되는 콜백을 추가합니다. 이는 직렬화해서는 안 되거나 직렬화할 수 없는 리소스를 해제하거나 사용자 데이터를 직렬화에 더 적합한 형태로 변환하는 데 사용할 수 있습니다.
콜백은 추가된 순서대로 실행됩니다.
v8.startupSnapshot.addDeserializeCallback(callback[, data])
추가된 버전: v18.6.0, v16.17.0
Node.js 인스턴스가 스냅샷에서 역직렬화될 때 호출되는 콜백을 추가합니다. callback
과 data
(제공된 경우)는 스냅샷으로 직렬화되며, 애플리케이션의 상태를 다시 초기화하거나 애플리케이션이 스냅샷에서 다시 시작될 때 필요한 리소스를 다시 획득하는 데 사용할 수 있습니다.
콜백은 추가된 순서대로 실행됩니다.
v8.startupSnapshot.setDeserializeMainFunction(callback[, data])
추가된 버전: v18.6.0, v16.17.0
스냅샷에서 역직렬화될 때 Node.js 애플리케이션의 진입점을 설정합니다. 이는 스냅샷 빌드 스크립트에서 한 번만 호출할 수 있습니다. 호출되면 역직렬화된 애플리케이션은 시작하기 위해 추가 진입점 스크립트가 더 이상 필요하지 않으며 역직렬화된 데이터(제공된 경우)와 함께 콜백을 호출합니다. 그렇지 않으면 역직렬화된 애플리케이션에 진입점 스크립트를 제공해야 합니다.
v8.startupSnapshot.isBuildingSnapshot()
추가된 버전: v18.6.0, v16.17.0
- 반환 값: <boolean>
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 데이터 수집을 중지하고 객체를 반환합니다. 객체의 내용은 다음과 같습니다.
{
"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
}
다음은 예시입니다.
const { GCProfiler } = require('node:v8')
const profiler = new GCProfiler()
profiler.start()
setTimeout(() => {
console.log(profiler.stop())
}, 1000)