diff --git a/src/node.cc b/src/node.cc index 12c28a5d0a2755..5ced5a3db62461 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 a54ead49eeda2a..72888ef36d519e 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 a3d446c2a51655..51adb816926e52 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 14aa68996f56cc..9fb5c3fd2855d3 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 5df9b04b394586..9ddc2201a6f412 100644 --- a/src/util.h +++ b/src/util.h @@ -53,6 +53,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 diff --git a/test/cctest/util.cc b/test/cctest/util.cc index f1446ae0345153..434eeba96f8445 100644 --- a/test/cctest/util.cc +++ b/test/cctest/util.cc @@ -90,6 +90,10 @@ TEST(UtilTest, ToLower) { EXPECT_EQ('a', ToLower('A')); } +namespace node { + void LowMemoryNotification() {} +} + TEST(UtilTest, Malloc) { using node::Malloc; EXPECT_NE(nullptr, Malloc(0));