From 3c345c2a032a4f88e750e5cc17cffeb9afca8d35 Mon Sep 17 00:00:00 2001 From: Maggie Nolan Date: Thu, 22 Oct 2020 13:08:04 -0700 Subject: [PATCH 1/2] work around V8 memory leak --- bindings/profiler.cc | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/bindings/profiler.cc b/bindings/profiler.cc index 11327fc1..80cbd275 100644 --- a/bindings/profiler.cc +++ b/bindings/profiler.cc @@ -96,8 +96,14 @@ NAN_METHOD(GetAllocationProfile) { } // Time profiler - -#if NODE_MODULE_VERSION > NODE_8_0_MODULE_VERSION +#if NODE_MODULE_VERSION >= NODE_12_0_MODULE_VERSION +// For Node 12 and Node 14, a new CPU profiler object will be created each +// time profiling is started to work around +// https://bugs.chromium.org/p/v8/issues/detail?id=11051. +CpuProfiler* cpuProfiler; +// Default sampling interval is 1000us. +int samplingIntervalUS = 1000; +#elif NODE_MODULE_VERSION > NODE_8_0_MODULE_VERSION // This profiler exists for the lifetime of the program. Not calling // CpuProfiler::Dispose() is intentional. CpuProfiler* cpuProfiler = CpuProfiler::New(v8::Isolate::GetCurrent()); @@ -264,6 +270,21 @@ NAN_METHOD(StartProfiling) { return Nan::ThrowTypeError("Second argument must be a boolean."); } +#if NODE_MODULE_VERSION >= NODE_12_0_MODULE_VERSION + // Since the CPU profiler is created and destroyed each time a CPU + // profile is collected, there cannot be multiple CPU profiling requests + // inflight in parallel. + if (cpuProfiler) { + return Nan::ThrowError("CPU profiler is already started."); + } + cpuProfiler = CpuProfiler::New(v8::Isolate::GetCurrent()); + // The default sampling interval is 1000us. If the sampling interval is + // different, set the sampling interval. + if (samplingIntervalUS != 1000) { + cpuProfiler->SetSamplingInterval(samplingIntervalUS); + } +#endif + Local name = Nan::MaybeLocal(info[0].As()).ToLocalChecked(); @@ -289,6 +310,11 @@ NAN_METHOD(StartProfiling) { // Signature: // stopProfiling(runName: string, includeLineInfo: boolean): TimeProfile NAN_METHOD(StopProfiling) { +#if NODE_MODULE_VERSION >= NODE_12_0_MODULE_VERSION + if (!cpuProfiler) { + return Nan::ThrowError("CPU profiler is not started."); + } +#endif if (info.Length() != 2) { return Nan::ThrowTypeError("StopProfling must have two arguments."); } @@ -307,6 +333,11 @@ NAN_METHOD(StopProfiling) { Local translated_profile = TranslateTimeProfile(profile, includeLineInfo); profile->Delete(); +#if NODE_MODULE_VERSION >= NODE_12_0_MODULE_VERSION + // Dispose of CPU profiler to work around memory leak. + cpuProfiler->Dispose(); + cpuProfiler = NULL; +#endif info.GetReturnValue().Set(translated_profile); } @@ -318,7 +349,11 @@ NAN_METHOD(SetSamplingInterval) { #else int us = info[0].As()->IntegerValue(); #endif +#if NODE_MODULE_VERSION >= NODE_12_0_MODULE_VERSION + samplingIntervalUS = us; +#else cpuProfiler->SetSamplingInterval(us); +#endif } NAN_MODULE_INIT(InitAll) { From 9612cc88032a846dec9227e5d41cfa5b161544fd Mon Sep 17 00:00:00 2001 From: Maggie Nolan Date: Thu, 29 Oct 2020 12:00:07 -0700 Subject: [PATCH 2/2] address comments --- bindings/profiler.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/bindings/profiler.cc b/bindings/profiler.cc index 80cbd275..cab84fc7 100644 --- a/bindings/profiler.cc +++ b/bindings/profiler.cc @@ -278,11 +278,7 @@ NAN_METHOD(StartProfiling) { return Nan::ThrowError("CPU profiler is already started."); } cpuProfiler = CpuProfiler::New(v8::Isolate::GetCurrent()); - // The default sampling interval is 1000us. If the sampling interval is - // different, set the sampling interval. - if (samplingIntervalUS != 1000) { - cpuProfiler->SetSamplingInterval(samplingIntervalUS); - } + cpuProfiler->SetSamplingInterval(samplingIntervalUS); #endif Local name = @@ -312,7 +308,7 @@ NAN_METHOD(StartProfiling) { NAN_METHOD(StopProfiling) { #if NODE_MODULE_VERSION >= NODE_12_0_MODULE_VERSION if (!cpuProfiler) { - return Nan::ThrowError("CPU profiler is not started."); + return Nan::ThrowError("StopProfiling called without an active CPU profiler."); } #endif if (info.Length() != 2) {