Skip to content

Buffer/Uint8Array using lots of memory #173

Closed
@SeanReece

Description

@SeanReece

Tested in NodeJS Versions: v22.3.0, v20.14.0, v18.20.3, v16.20.2

It appears as though Buffer/Uint8Array consumes much more memory than I would expect. This is particularly obvious with many small instances.

For example:

const data = new Uint8Array(12) <-- I would think this would consume ~12bytes

It appears to have a shallow size of 96bytes and retains 196bytes
image

I'm not sure if this is a V8 issue but when I try the same in Chrome 126 I see a similar issue but it uses slightly less memory

image

Why this is an issue

I stumbled on this while trying to profile memory issues while pulling large amounts of MongoDB documents into memory, even projecting the documents to just return 2 ObjectIds each (we're building potentially large graphs in memory from the links).

A BSON ObjectId is 12 bytes. So we estimated ~24MB per million edges. (maybe a bit more for object overhead etc)
In reality this uses almost 500MB

At first I thought this was an issue with BSON's implementation but this can be recreated using Uint8Array directly.

Try it out

const arr = []

const heapBefore = process.memoryUsage().heapUsed
for (let i = 0; i < 2000000; i++) {
  arr.push(new Uint8Array(12)) // Same with Buffer.alloc(12)
}
const heapAfter = process.memoryUsage().heapUsed   // Not super accurate but illustrates the issue
const size = Math.round((heapAfter - heapBefore) / 1024 / 1024)
console.log(`Used ${size}MB to store ${arr.length} Uint8Array(12)`)
// Used 473MB to store 2000000 Uint8Array(12)

It doesn't appear that the memory used increases much with the size of the Uint8Array. Doubling the size of each Uint8Array from 12 -> 24 only increases the memory usage to 485MB in the above test. This tells me there's probably some overhead in the data structure itself than some data being duplicated or something.

Curiously, when I try the same thing with Buffer.from(new Uint8Array(12)) it only outputs ~240MB. I assume this is because buffer doesn't keep a reference to something(?) and GC happens sometime before capturing heapUsed.

See below when using Buffer.from(new Uint8Array(12)) it retains 100bytes less 🤔
Screenshot 2024-06-13 at 2 15 53 PM

Thanks

Big thanks to the Node.js Performance Team in advance. You're doing amazing work 👍 Please let me know if this is an issue with V8 directly or if this is completely expected behaviour. It really caught me off guard.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions