From fcc6c57354768a86941fe521acab0df909a553bb Mon Sep 17 00:00:00 2001 From: Geoffrey Kruse <6468053+doggkruse@users.noreply.github.com> Date: Sun, 26 Jun 2022 18:00:23 -0700 Subject: [PATCH 1/2] Change to using std::min() when allocating Buffers on the C++ side. This will result in Buffers being allocated to the size requested up to kMaxLength (0x3fffffff) instead of the current behavior of always allocating kMaxLength. Since these buffers are allocated in the node external memory (limited to 64M) the old behavior would very quickly cause massive GC pressure as the GC is triggered on each new Buffer allocation once the node external memory limit is reached. It appears the old behavior was not intentional and should have always been std::min(). This should fix https://github.com/node-ffi-napi/ref-napi/issues/72 --- src/binding.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/binding.cc b/src/binding.cc index abd43ae..892b78c 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -141,7 +141,7 @@ class InstanceData final : public RefNapi::Instance { ab = it->second.ab.Value(); if (ab.IsEmpty()) { - length = std::max(length, kMaxLength); + length = std::min(length, kMaxLength); ab = Buffer::New(env, ptr, length, [this](Env env, char* ptr) { UnregisterArrayBuffer(ptr); }).ArrayBuffer(); From 1691d10f917c225ac391a36536479615672facf2 Mon Sep 17 00:00:00 2001 From: Geoffrey Kruse <6468053+doggkruse@users.noreply.github.com> Date: Sun, 26 Jun 2022 20:04:19 -0700 Subject: [PATCH 2/2] Handle case where the previously allocated array buffer is shorter than the current request. This is likely what drove the problematic max size allocation --- src/binding.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/binding.cc b/src/binding.cc index 892b78c..fb28efd 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -105,12 +105,12 @@ class InstanceData final : public RefNapi::Instance { auto it = pointer_to_orig_buffer.find(ptr); if (it != pointer_to_orig_buffer.end()) { + it->second.finalizer_count++; if (!it->second.ab.Value().IsEmpty()) { // Already have a valid entry, nothing to do. return; } it->second.ab.Reset(buf, 0); - it->second.finalizer_count++; } else { pointer_to_orig_buffer.emplace(ptr, ArrayBufferEntry { Reference::New(buf, 0), @@ -140,7 +140,7 @@ class InstanceData final : public RefNapi::Instance { if (it != pointer_to_orig_buffer.end()) ab = it->second.ab.Value(); - if (ab.IsEmpty()) { + if (ab.IsEmpty() || (ab.ByteLength() < length)) { length = std::min(length, kMaxLength); ab = Buffer::New(env, ptr, length, [this](Env env, char* ptr) { UnregisterArrayBuffer(ptr);