Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 90e8977

Browse filesBrowse files
theanarkhRafaelGSS
authored andcommitted
v8: add setHeapSnapshotNearHeapLimit
PR-URL: #44420 Refs: #33010 Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
1 parent e8101af commit 90e8977
Copy full SHA for 90e8977
Expand file treeCollapse file tree

12 files changed

+294
-17
lines changed
Open diff view settings
Collapse file

‎doc/api/v8.md‎

Copy file name to clipboardExpand all lines: doc/api/v8.md
+15Lines changed: 15 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,20 @@ if (isMainThread) {
356356
}
357357
```
358358

359+
## `v8.setHeapSnapshotNearHeapLimit(limit)`
360+
361+
<!-- YAML
362+
added: REPLACEME
363+
-->
364+
365+
> Stability: 1 - Experimental
366+
367+
* `limit` {integer}
368+
369+
The API is a no-op if `--heapsnapshot-near-heap-limit` is already set from the
370+
command line or the API is called more than once. `limit` must be a positive
371+
integer. See [`--heapsnapshot-near-heap-limit`][] for more information.
372+
359373
## Serialization API
360374

361375
The serialization API provides means of serializing JavaScript values in a way
@@ -1010,6 +1024,7 @@ Returns true if the Node.js instance is run to build a snapshot.
10101024
[HTML structured clone algorithm]: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm
10111025
[Hook Callbacks]: #hook-callbacks
10121026
[V8]: https://developers.google.com/v8/
1027+
[`--heapsnapshot-near-heap-limit`]: cli.md#--heapsnapshot-near-heap-limitmax_count
10131028
[`AsyncLocalStorage`]: async_context.md#class-asynclocalstorage
10141029
[`Buffer`]: buffer.md
10151030
[`DefaultDeserializer`]: #class-v8defaultdeserializer
Collapse file

‎lib/v8.js‎

Copy file name to clipboardExpand all lines: lib/v8.js
+17-2Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ const {
3333
} = primordials;
3434

3535
const { Buffer } = require('buffer');
36-
const { validateString } = require('internal/validators');
36+
const { validateString, validateUint32 } = require('internal/validators');
3737
const {
3838
Serializer,
3939
Deserializer
@@ -59,6 +59,7 @@ const {
5959
} = internalBinding('heap_utils');
6060
const { HeapSnapshotStream } = require('internal/heap_utils');
6161
const promiseHooks = require('internal/promise_hooks');
62+
const { getOptionValue } = require('internal/options');
6263

6364
/**
6465
* Generates a snapshot of the current V8 heap
@@ -95,6 +96,7 @@ const {
9596
updateHeapStatisticsBuffer,
9697
updateHeapSpaceStatisticsBuffer,
9798
updateHeapCodeStatisticsBuffer,
99+
setHeapSnapshotNearHeapLimit: _setHeapSnapshotNearHeapLimit,
98100

99101
// Properties for heap statistics buffer extraction.
100102
kTotalHeapSizeIndex,
@@ -226,6 +228,18 @@ function getHeapCodeStatistics() {
226228
};
227229
}
228230

231+
let heapSnapshotNearHeapLimitCallbackAdded = false;
232+
function setHeapSnapshotNearHeapLimit(limit) {
233+
validateUint32(limit, 'limit', 1);
234+
if (heapSnapshotNearHeapLimitCallbackAdded ||
235+
getOptionValue('--heapsnapshot-near-heap-limit') > 0
236+
) {
237+
return;
238+
}
239+
heapSnapshotNearHeapLimitCallbackAdded = true;
240+
_setHeapSnapshotNearHeapLimit(limit);
241+
}
242+
229243
/* V8 serialization API */
230244

231245
/* JS methods for the base objects */
@@ -387,5 +401,6 @@ module.exports = {
387401
serialize,
388402
writeHeapSnapshot,
389403
promiseHooks,
390-
startupSnapshot
404+
startupSnapshot,
405+
setHeapSnapshotNearHeapLimit,
391406
};
Collapse file

‎src/env-inl.h‎

Copy file name to clipboardExpand all lines: src/env-inl.h
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,24 @@ v8::Local<v8::Context> Environment::context() const {
900900
return PersistentToLocal::Strong(context_);
901901
}
902902

903+
inline void Environment::set_heap_snapshot_near_heap_limit(uint32_t limit) {
904+
heap_snapshot_near_heap_limit_ = limit;
905+
}
906+
907+
inline void Environment::AddHeapSnapshotNearHeapLimitCallback() {
908+
DCHECK(!heapsnapshot_near_heap_limit_callback_added_);
909+
heapsnapshot_near_heap_limit_callback_added_ = true;
910+
isolate_->AddNearHeapLimitCallback(Environment::NearHeapLimitCallback, this);
911+
}
912+
913+
inline void Environment::RemoveHeapSnapshotNearHeapLimitCallback(
914+
size_t heap_limit) {
915+
DCHECK(heapsnapshot_near_heap_limit_callback_added_);
916+
heapsnapshot_near_heap_limit_callback_added_ = false;
917+
isolate_->RemoveNearHeapLimitCallback(Environment::NearHeapLimitCallback,
918+
heap_limit);
919+
}
920+
903921
} // namespace node
904922

905923
// These two files depend on each other. Including base_object-inl.h after this
Collapse file

‎src/env.cc‎

Copy file name to clipboardExpand all lines: src/env.cc
+9-10Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,9 @@ Environment::Environment(IsolateData* isolate_data,
704704
inspector_host_port_ = std::make_shared<ExclusiveAccess<HostPort>>(
705705
options_->debug_options().host_port);
706706

707+
heap_snapshot_near_heap_limit_ =
708+
static_cast<uint32_t>(options_->heap_snapshot_near_heap_limit);
709+
707710
if (!(flags_ & EnvironmentFlags::kOwnsProcessState)) {
708711
set_abort_on_uncaught_exception(false);
709712
}
@@ -818,9 +821,8 @@ Environment::~Environment() {
818821
// FreeEnvironment() should have set this.
819822
CHECK(is_stopping());
820823

821-
if (options_->heap_snapshot_near_heap_limit > heap_limit_snapshot_taken_) {
822-
isolate_->RemoveNearHeapLimitCallback(Environment::NearHeapLimitCallback,
823-
0);
824+
if (heapsnapshot_near_heap_limit_callback_added_) {
825+
RemoveHeapSnapshotNearHeapLimitCallback(0);
824826
}
825827

826828
isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
@@ -1905,8 +1907,7 @@ size_t Environment::NearHeapLimitCallback(void* data,
19051907
Debug(env,
19061908
DebugCategory::DIAGNOSTICS,
19071909
"Not generating snapshots because it's too risky.\n");
1908-
env->isolate()->RemoveNearHeapLimitCallback(NearHeapLimitCallback,
1909-
initial_heap_limit);
1910+
env->RemoveHeapSnapshotNearHeapLimitCallback(initial_heap_limit);
19101911
// The new limit must be higher than current_heap_limit or V8 might
19111912
// crash.
19121913
return current_heap_limit + 1;
@@ -1926,17 +1927,15 @@ size_t Environment::NearHeapLimitCallback(void* data,
19261927

19271928
// Remove the callback first in case it's triggered when generating
19281929
// the snapshot.
1929-
env->isolate()->RemoveNearHeapLimitCallback(NearHeapLimitCallback,
1930-
initial_heap_limit);
1930+
env->RemoveHeapSnapshotNearHeapLimitCallback(initial_heap_limit);
19311931

19321932
heap::WriteSnapshot(env, filename.c_str());
19331933
env->heap_limit_snapshot_taken_ += 1;
19341934

19351935
// Don't take more snapshots than the number specified by
19361936
// --heapsnapshot-near-heap-limit.
1937-
if (env->heap_limit_snapshot_taken_ <
1938-
env->options_->heap_snapshot_near_heap_limit) {
1939-
env->isolate()->AddNearHeapLimitCallback(NearHeapLimitCallback, env);
1937+
if (env->heap_limit_snapshot_taken_ < env->heap_snapshot_near_heap_limit_) {
1938+
env->AddHeapSnapshotNearHeapLimitCallback();
19401939
}
19411940

19421941
FPrintF(stderr, "Wrote snapshot to %s\n", filename.c_str());
Collapse file

‎src/env.h‎

Copy file name to clipboardExpand all lines: src/env.h
+9-1Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,12 @@ class Environment : public MemoryRetainer {
14321432
template <typename T>
14331433
void ForEachBindingData(T&& iterator);
14341434

1435+
inline void set_heap_snapshot_near_heap_limit(uint32_t limit);
1436+
1437+
inline void AddHeapSnapshotNearHeapLimitCallback();
1438+
1439+
inline void RemoveHeapSnapshotNearHeapLimitCallback(size_t heap_limit);
1440+
14351441
private:
14361442
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
14371443
const char* errmsg);
@@ -1489,7 +1495,9 @@ class Environment : public MemoryRetainer {
14891495
std::string exec_path_;
14901496

14911497
bool is_processing_heap_limit_callback_ = false;
1492-
int64_t heap_limit_snapshot_taken_ = 0;
1498+
uint32_t heap_limit_snapshot_taken_ = 0;
1499+
uint32_t heap_snapshot_near_heap_limit_ = 0;
1500+
bool heapsnapshot_near_heap_limit_callback_added_ = false;
14931501

14941502
uint32_t module_id_counter_ = 0;
14951503
uint32_t script_id_counter_ = 0;
Collapse file

‎src/node.cc‎

Copy file name to clipboardExpand all lines: src/node.cc
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,8 @@ static void AtomicsWaitCallback(Isolate::AtomicsWaitEvent event,
277277
void Environment::InitializeDiagnostics() {
278278
isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
279279
Environment::BuildEmbedderGraph, this);
280-
if (options_->heap_snapshot_near_heap_limit > 0) {
281-
isolate_->AddNearHeapLimitCallback(Environment::NearHeapLimitCallback,
282-
this);
280+
if (heap_snapshot_near_heap_limit_ > 0) {
281+
AddHeapSnapshotNearHeapLimitCallback();
283282
}
284283
if (options_->trace_uncaught)
285284
isolate_->SetCaptureStackTraceForUncaughtExceptions(true);
Collapse file

‎src/node_v8.cc‎

Copy file name to clipboardExpand all lines: src/node_v8.cc
+14Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ void CachedDataVersionTag(const FunctionCallbackInfo<Value>& args) {
153153
args.GetReturnValue().Set(result);
154154
}
155155

156+
void SetHeapSnapshotNearHeapLimit(const FunctionCallbackInfo<Value>& args) {
157+
CHECK(args[0]->IsUint32());
158+
Environment* env = Environment::GetCurrent(args);
159+
uint32_t limit = args[0].As<v8::Uint32>()->Value();
160+
CHECK_GT(limit, 0);
161+
env->AddHeapSnapshotNearHeapLimitCallback();
162+
env->set_heap_snapshot_near_heap_limit(limit);
163+
}
164+
156165
void UpdateHeapStatisticsBuffer(const FunctionCallbackInfo<Value>& args) {
157166
BindingData* data = Environment::GetBindingData<BindingData>(args);
158167
HeapStatistics s;
@@ -208,6 +217,10 @@ void Initialize(Local<Object> target,
208217

209218
SetMethodNoSideEffect(
210219
context, target, "cachedDataVersionTag", CachedDataVersionTag);
220+
SetMethodNoSideEffect(context,
221+
target,
222+
"setHeapSnapshotNearHeapLimit",
223+
SetHeapSnapshotNearHeapLimit);
211224
SetMethod(context,
212225
target,
213226
"updateHeapStatisticsBuffer",
@@ -263,6 +276,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
263276
registry->Register(UpdateHeapCodeStatisticsBuffer);
264277
registry->Register(UpdateHeapSpaceStatisticsBuffer);
265278
registry->Register(SetFlagsFromString);
279+
registry->Register(SetHeapSnapshotNearHeapLimit);
266280
}
267281

268282
} // namespace v8_utils
Collapse file
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
'use strict';
2+
const path = require('path');
3+
const v8 = require('v8');
4+
5+
v8.setHeapSnapshotNearHeapLimit(+process.env.limit);
6+
if (process.env.limit2) {
7+
v8.setHeapSnapshotNearHeapLimit(+process.env.limit2);
8+
}
9+
require(path.resolve(__dirname, 'grow.js'));
Collapse file
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
const path = require('path');
3+
const { Worker } = require('worker_threads');
4+
const max_snapshots = parseInt(process.env.TEST_SNAPSHOTS) || 1;
5+
new Worker(path.join(__dirname, 'grow-and-set-near-heap-limit.js'), {
6+
env: {
7+
...process.env,
8+
limit: max_snapshots,
9+
},
10+
resourceLimits: {
11+
maxOldGenerationSizeMb:
12+
parseInt(process.env.TEST_OLD_SPACE_SIZE) || 20
13+
}
14+
});
15+
Collapse file
+41Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copy from test-heapsnapshot-near-heap-limit-worker.js
2+
'use strict';
3+
4+
require('../common');
5+
const tmpdir = require('../common/tmpdir');
6+
const assert = require('assert');
7+
const { spawnSync } = require('child_process');
8+
const fixtures = require('../common/fixtures');
9+
const fs = require('fs');
10+
11+
const env = {
12+
...process.env,
13+
NODE_DEBUG_NATIVE: 'diagnostics'
14+
};
15+
16+
{
17+
tmpdir.refresh();
18+
const child = spawnSync(process.execPath, [
19+
fixtures.path('workload', 'grow-worker-and-set-near-heap-limit.js'),
20+
], {
21+
cwd: tmpdir.path,
22+
env: {
23+
TEST_SNAPSHOTS: 1,
24+
TEST_OLD_SPACE_SIZE: 50,
25+
...env
26+
}
27+
});
28+
console.log(child.stdout.toString());
29+
const stderr = child.stderr.toString();
30+
console.log(stderr);
31+
const risky = /Not generating snapshots because it's too risky/.test(stderr);
32+
if (!risky) {
33+
// There should be one snapshot taken and then after the
34+
// snapshot heap limit callback is popped, the OOM callback
35+
// becomes effective.
36+
assert(stderr.includes('ERR_WORKER_OUT_OF_MEMORY'));
37+
const list = fs.readdirSync(tmpdir.path)
38+
.filter((file) => file.endsWith('.heapsnapshot'));
39+
assert.strictEqual(list.length, 1);
40+
}
41+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.