From a2be03608dae22ca12962837bc6f8053eb3e0b75 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 21 Apr 2021 12:53:01 -0700 Subject: [PATCH] doc: add note about deferred buffer deallocation Signed-off-by: James M Snell Refs: https://github.com/nodejs/node/issues/38300 --- doc/api/buffer.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 7e75e33a270a52..d2674f5f9166bf 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -874,6 +874,37 @@ console.log(buf1.toString('latin1')); A `TypeError` will be thrown if `string` is not a string or another type appropriate for `Buffer.from()` variants. +#### Memory and garbage collection considerations + +When creating a {Buffer} from a large string using `Buffer.from()`, Node.js +may allocate the backing memory storage separately from the v8 heap. In such +cases, when the {Buffer} is garbage collected, the backing memory is not +immediately freed. Instead, the freeing the memory is queued and deferred +to run after the currently executing JavaScript context has completed and +the Node.js event loop is allowed to turn, causing memory to be held on to +by the process for longer than a developer may expect. + +For example, in the following pathological example, multiple large {Buffer}s +are created in a synchronous for loop. Despite those {Buffer}s being garbage +collected successfully, the backing memory is not freed until after the +complete script runs: + +```js +const str = 'a'.repeat(4096); +for (let n = 0; n < 1e6; n++) { + // We are not retaining a reference to the Buffer so + // gc should clean it up! + Buffer.from(str); + gc(); +} +gc(); +``` + +Aside from not allocating large {Buffer}s in synchronous for-loops, it is +recommended that code working with large {Buffer} objects created from +large strings active allow the event loop to turn to reduce the impact of +the deferred deallocations. + ### Static method: `Buffer.isBuffer(obj)`