From 72c60e892c6f5ca309e20953e032a590be7787db Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 10 Sep 2016 18:21:20 +0200 Subject: src: notify V8 for low memory when alloc fails Call `v8::Isolate::GetCurrent()->LowMemoryNotification()` when an allocation fails to give V8 a chance to clean up and return memory before retrying (and possibly giving up). PR-URL: https://github.com/nodejs/node/pull/8482 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Michael Dawson Reviewed-By: Ilkka Myller --- src/node.cc | 4 ++++ src/node_internals.h | 3 +++ src/util-inl.h | 10 +++++++++- src/util.cc | 9 +++++++++ src/util.h | 5 +++++ 5 files changed, 30 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/node.cc b/src/node.cc index 12c28a5d0a..5ced5a3db6 100644 --- a/src/node.cc +++ b/src/node.cc @@ -183,6 +183,8 @@ bool trace_warnings = false; // that is used by lib/module.js bool config_preserve_symlinks = false; +bool v8_initialized = false; + // process-relative uptime base, initialized at start-up static double prog_start_time; static bool debugger_running; @@ -4490,6 +4492,7 @@ int Start(int argc, char** argv) { v8_platform.Initialize(v8_thread_pool_size); V8::Initialize(); + v8_initialized = true; int exit_code = 1; { @@ -4503,6 +4506,7 @@ int Start(int argc, char** argv) { StartNodeInstance(&instance_data); exit_code = instance_data.exit_code(); } + v8_initialized = false; V8::Dispose(); v8_platform.Dispose(); diff --git a/src/node_internals.h b/src/node_internals.h index a54ead49ee..72888ef36d 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -37,6 +37,9 @@ namespace node { // that is used by lib/module.js extern bool config_preserve_symlinks; +// Tells whether it is safe to call v8::Isolate::GetCurrent(). +extern bool v8_initialized; + // Forward declaration class Environment; diff --git a/src/util-inl.h b/src/util-inl.h index a3d446c2a5..51adb81692 100644 --- a/src/util-inl.h +++ b/src/util-inl.h @@ -253,7 +253,15 @@ T* UncheckedRealloc(T* pointer, size_t n) { return nullptr; } - return static_cast(realloc(pointer, full_size)); + void* allocated = realloc(pointer, full_size); + + if (UNLIKELY(allocated == nullptr)) { + // Tell V8 that memory is low and retry. + LowMemoryNotification(); + allocated = realloc(pointer, full_size); + } + + return static_cast(allocated); } // As per spec realloc behaves like malloc if passed nullptr. diff --git a/src/util.cc b/src/util.cc index 14aa68996f..9fb5c3fd28 100644 --- a/src/util.cc +++ b/src/util.cc @@ -77,4 +77,13 @@ BufferValue::BufferValue(Isolate* isolate, Local value) { } } +void LowMemoryNotification() { + if (v8_initialized) { + auto isolate = v8::Isolate::GetCurrent(); + if (isolate != nullptr) { + isolate->LowMemoryNotification(); + } + } +} + } // namespace node diff --git a/src/util.h b/src/util.h index dba5824894..25f2eb0178 100644 --- a/src/util.h +++ b/src/util.h @@ -44,6 +44,11 @@ inline char* Calloc(size_t n) { return Calloc(n); } inline char* UncheckedMalloc(size_t n) { return UncheckedMalloc(n); } inline char* UncheckedCalloc(size_t n) { return UncheckedCalloc(n); } +// Used by the allocation functions when allocation fails. +// Thin wrapper around v8::Isolate::LowMemoryNotification() that checks +// whether V8 is initialized. +void LowMemoryNotification(); + #ifdef __GNUC__ #define NO_RETURN __attribute__((noreturn)) #else -- cgit v1.2.3