diff --git a/src/env.cc b/src/env.cc index 87340112fbe..f9fd8f7951b 100644 --- a/src/env.cc +++ b/src/env.cc @@ -77,6 +77,8 @@ using v8::Undefined; using v8::Value; using worker::Worker; +constexpr size_t kManagedBufferCacheSize = 64 * 1024; + int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64; void* const ContextEmbedderTag::kNodeContextTagPtr = const_cast( static_cast(&ContextEmbedderTag::kNodeContextTag)); @@ -746,10 +748,16 @@ void Environment::add_refs(int64_t diff) { } uv_buf_t Environment::allocate_managed_buffer(const size_t suggested_size) { - std::unique_ptr bs = ArrayBuffer::NewBackingStore( - isolate(), - suggested_size, - BackingStoreInitializationMode::kUninitialized); + std::unique_ptr bs; + if (suggested_size == kManagedBufferCacheSize && + managed_buffer_cache_ != nullptr) { + bs = std::move(managed_buffer_cache_); + } else { + bs = ArrayBuffer::NewBackingStore( + isolate(), + suggested_size, + BackingStoreInitializationMode::kUninitialized); + } uv_buf_t buf = uv_buf_init(static_cast(bs->Data()), bs->ByteLength()); released_allocated_buffers_.emplace(buf.base, std::move(bs)); return buf; @@ -767,6 +775,11 @@ std::unique_ptr Environment::release_managed_buffer( return bs; } +void Environment::recycle_managed_buffer(std::unique_ptr bs) { + if (bs != nullptr && bs->ByteLength() == kManagedBufferCacheSize) + managed_buffer_cache_ = std::move(bs); +} + std::string Environment::GetExecPath(const std::vector& argv) { char exec_path_buf[2 * PATH_MAX]; size_t exec_path_len = sizeof(exec_path_buf); diff --git a/src/env.h b/src/env.h index c2caf979023..ca96caffaca 100644 --- a/src/env.h +++ b/src/env.h @@ -1041,6 +1041,9 @@ class Environment final : public MemoryRetainer { uv_buf_t allocate_managed_buffer(const size_t suggested_size); std::unique_ptr release_managed_buffer(const uv_buf_t& buf); + // Only buffers that were not exposed externally may be recycled. + void recycle_managed_buffer( + std::unique_ptr backing_store); void AddUnmanagedFd(int fd); void RemoveUnmanagedFd(int fd); @@ -1257,6 +1260,9 @@ class Environment final : public MemoryRetainer { std::unordered_map> released_allocated_buffers_; + // Retains at most one unexposed read buffer for reuse. + std::unique_ptr managed_buffer_cache_; + v8::CpuProfiler* cpu_profiler_ = nullptr; std::vector pending_profiles_; }; diff --git a/src/stream_base.cc b/src/stream_base.cc index 370b8f682ea..0791dcf81eb 100644 --- a/src/stream_base.cc +++ b/src/stream_base.cc @@ -697,6 +697,7 @@ void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { std::unique_ptr bs = env->release_managed_buffer(buf_); if (nread <= 0) { + env->recycle_managed_buffer(std::move(bs)); if (nread < 0) stream->CallJSOnreadMethod(nread, Local()); return; @@ -708,6 +709,7 @@ void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf_) { bs = ArrayBuffer::NewBackingStore( isolate, nread, BackingStoreInitializationMode::kUninitialized); memcpy(bs->Data(), old_bs->Data(), nread); + env->recycle_managed_buffer(std::move(old_bs)); } stream->CallJSOnreadMethod(nread, ArrayBuffer::New(isolate, std::move(bs)));