From a6f8f3f3702c17cd14c4b4a8f6e809959a054079 Mon Sep 17 00:00:00 2001 From: NickNaso Date: Tue, 19 Jun 2018 01:04:43 +0200 Subject: [PATCH 1/2] Add memory mangament feature For more info see the following issue: https://github.com/nodejs/node-addon-api/issues/260 --- README.md | 1 + doc/memory_management.md | 27 +++++++++++++++++++++++++++ napi-inl.h | 11 +++++++++++ napi.h | 8 ++++++++ package.json | 2 +- test/binding.cc | 2 ++ test/binding.gyp | 1 + test/index.js | 1 + test/memory_management.cc | 17 +++++++++++++++++ test/memory_management.js | 10 ++++++++++ 10 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 doc/memory_management.md create mode 100644 test/memory_management.cc create mode 100644 test/memory_management.js diff --git a/README.md b/README.md index fb6308ad7..c31922b40 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ values. Concepts and operations generally map to ideas specified in the - [ArrayBuffer](doc/array_buffer.md) - [TypedArray](doc/typed_array.md) - [TypedArrayOf](doc/typed_array_of.md) + - [Memory Management](doc/memory_management.md) - [Async Operations](doc/async_operations.md) - [AsyncWorker](doc/async_worker.md) - [Promises](doc/promises.md) diff --git a/doc/memory_management.md b/doc/memory_management.md new file mode 100644 index 000000000..a2ba1154b --- /dev/null +++ b/doc/memory_management.md @@ -0,0 +1,27 @@ +# MemoryManagement + +The `MemoryManagement` class contains functions that give the JavaScript engine +an indication of the amount of externally allocated memory that is kept alive by +JavaScript objects. + +## Methods + +### AdjustExternalMemory + +The function `AdjustExternalMemory` adjusts the amount of registered external +memory. Used to give the JavaScript engine an indication of the amount of externally +allocated memory that is kept alive by JavaScript objects. +The JavaScript engine uses this to decide when to perform global garbage collections. +Registering externally allocated memory will trigger global garbage collections +more often than it would otherwise in an attempt to garbage collect the JavaScript +objects that keep the externally allocated memory alive. + +```cpp +static int64_t MemoryManagement::AdjustExternalMemory(Env env, int64_t change_in_bytes); +``` + +- `[in] env`: The environment in which the API is inoked under. +- `[in] change_in_bytes`: The change in externally allocated memory that is kept +alive by JavaScript objects expressed in bytes. + +Returns the adjusted memory value. diff --git a/napi-inl.h b/napi-inl.h index 77e4d5584..46ba2c0b9 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -3224,6 +3224,17 @@ inline void AsyncWorker::OnWorkComplete( delete self; } +//////////////////////////////////////////////////////////////////////////////// +// Memory Management class +//////////////////////////////////////////////////////////////////////////////// + +inline int64_t MemoryManagement::AdjustExternalMemory(Env env, int64_t change_in_bytes) { + int64_t result; + napi_status status = napi_adjust_external_memory(env, change_in_bytes, &result); + NAPI_THROW_IF_FAILED(env, status, 0); + return result; +} + // These macros shouldn't be useful in user code. #undef NAPI_THROW #undef NAPI_THROW_IF_FAILED diff --git a/napi.h b/napi.h index 0aa9a6af1..f9852968b 100644 --- a/napi.h +++ b/napi.h @@ -76,6 +76,8 @@ namespace Napi { /// Defines the signature of a N-API C++ module's registration callback (init) function. typedef Object (*ModuleRegisterCallback)(Env env, Object exports); + class MemoryManagement; + /// Environment for N-API values and operations. /// /// All N-API values and operations must be associated with an environment. An environment @@ -1549,6 +1551,12 @@ namespace Napi { std::string _error; }; + // Memory management. + class MemoryManagement { + public: + static int64_t AdjustExternalMemory(Env env, int64_t change_in_bytes); + }; + } // namespace Napi // Inline implementations of all the above class methods are included here. diff --git a/package.json b/package.json index 352cfc382..f1fdeb73a 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "Anna Henningsen (https://github.com/addaleax)", "Arunesh Chandra (https://github.com/aruneshchandra)", "Benjamin Byholm (https://github.com/kkoopa)", - "Cory Mickelson (https://github.com/corymickelson)", + "Cory Mickelson (https://github.com/corymickelson)", "David Halls (https://github.com/davedoesdev)", "Eric Bickle (https://github.com/ebickle)", "Gabriel Schulhof (https://github.com/gabrielschulhof)", diff --git a/test/binding.cc b/test/binding.cc index 8e6a1e9ec..0032c8e30 100644 --- a/test/binding.cc +++ b/test/binding.cc @@ -13,6 +13,7 @@ Object InitError(Env env); Object InitExternal(Env env); Object InitFunction(Env env); Object InitHandleScope(Env env); +Object InitMemoryManagement(Env env); Object InitName(Env env); Object InitObject(Env env); Object InitPromise(Env env); @@ -33,6 +34,7 @@ Object Init(Env env, Object exports) { exports.Set("function", InitFunction(env)); exports.Set("name", InitName(env)); exports.Set("handlescope", InitHandleScope(env)); + exports.Set("memory_management", InitMemoryManagement(env)); exports.Set("object", InitObject(env)); exports.Set("promise", InitPromise(env)); exports.Set("typedarray", InitTypedArray(env)); diff --git a/test/binding.gyp b/test/binding.gyp index 4e0050480..acbbc0a12 100644 --- a/test/binding.gyp +++ b/test/binding.gyp @@ -13,6 +13,7 @@ 'external.cc', 'function.cc', 'handlescope.cc', + 'memory_management.cc', 'name.cc', 'object/delete_property.cc', 'object/get_property.cc', diff --git a/test/index.js b/test/index.js index 5211bb467..c9d7fb0c2 100644 --- a/test/index.js +++ b/test/index.js @@ -19,6 +19,7 @@ let testModules = [ 'external', 'function', 'handlescope', + 'memory_management', 'name', 'object/delete_property', 'object/get_property', diff --git a/test/memory_management.cc b/test/memory_management.cc new file mode 100644 index 000000000..c571133a5 --- /dev/null +++ b/test/memory_management.cc @@ -0,0 +1,17 @@ +#include "napi.h" + +using namespace Napi; + +Value externalAllocatedMemory(const CallbackInfo& info) { + int64_t kSize = 1024 * 1024; + int64_t baseline = MemoryManagement::AdjustExternalMemory(info.Env(), 0); + int64_t tmp = MemoryManagement::AdjustExternalMemory(info.Env(), kSize); + tmp = MemoryManagement::AdjustExternalMemory(info.Env(), -kSize); + return Boolean::New(info.Env(), tmp == baseline); +} + +Object InitMemoryManagement(Env env) { + Object exports = Object::New(env); + exports["externalAllocatedMemory"] = Function::New(env, externalAllocatedMemory); + return exports; +} \ No newline at end of file diff --git a/test/memory_management.js b/test/memory_management.js new file mode 100644 index 000000000..7b0b63a2f --- /dev/null +++ b/test/memory_management.js @@ -0,0 +1,10 @@ +'use strict'; +const buildType = process.config.target_defaults.default_configuration; +const assert = require('assert'); + +test(require(`./build/${buildType}/binding.node`)); +test(require(`./build/${buildType}/binding_noexcept.node`)); + +function test(binding) { + assert.strictEqual(binding.memory_management.externalAllocatedMemory(), true) +} \ No newline at end of file From a4b8ea8c02c2345e7833164bb05ce5c70940dd3f Mon Sep 17 00:00:00 2001 From: NickNaso Date: Wed, 4 Jul 2018 15:43:20 +0200 Subject: [PATCH 2/2] Executed the changes requested after first review --- doc/memory_management.md | 6 +++--- test/memory_management.cc | 2 +- test/memory_management.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/memory_management.md b/doc/memory_management.md index a2ba1154b..2cabd57ca 100644 --- a/doc/memory_management.md +++ b/doc/memory_management.md @@ -1,7 +1,7 @@ # MemoryManagement The `MemoryManagement` class contains functions that give the JavaScript engine -an indication of the amount of externally allocated memory that is kept alive by +an indication of the amount of externally allocated memory that is kept alive by JavaScript objects. ## Methods @@ -9,7 +9,7 @@ JavaScript objects. ### AdjustExternalMemory The function `AdjustExternalMemory` adjusts the amount of registered external -memory. Used to give the JavaScript engine an indication of the amount of externally +memory used to give the JavaScript engine an indication of the amount of externally allocated memory that is kept alive by JavaScript objects. The JavaScript engine uses this to decide when to perform global garbage collections. Registering externally allocated memory will trigger global garbage collections @@ -20,7 +20,7 @@ objects that keep the externally allocated memory alive. static int64_t MemoryManagement::AdjustExternalMemory(Env env, int64_t change_in_bytes); ``` -- `[in] env`: The environment in which the API is inoked under. +- `[in] env`: The environment in which the API is invoked under. - `[in] change_in_bytes`: The change in externally allocated memory that is kept alive by JavaScript objects expressed in bytes. diff --git a/test/memory_management.cc b/test/memory_management.cc index c571133a5..a42357539 100644 --- a/test/memory_management.cc +++ b/test/memory_management.cc @@ -14,4 +14,4 @@ Object InitMemoryManagement(Env env) { Object exports = Object::New(env); exports["externalAllocatedMemory"] = Function::New(env, externalAllocatedMemory); return exports; -} \ No newline at end of file +} diff --git a/test/memory_management.js b/test/memory_management.js index 7b0b63a2f..f4911a2a6 100644 --- a/test/memory_management.js +++ b/test/memory_management.js @@ -7,4 +7,4 @@ test(require(`./build/${buildType}/binding_noexcept.node`)); function test(binding) { assert.strictEqual(binding.memory_management.externalAllocatedMemory(), true) -} \ No newline at end of file +}