Skip to content

unbounded memory usage in unyielding JS jobs creating ObjectWrap-ed native objects #1140

Closed
@MichaelBelousov

Description

@MichaelBelousov

See this minimal reproduction repository.

When creating several instances of a C++ object that is wrapped by ObjectWrap, memory usage goes up forever unless the JavaScript job yields. Even though the JavaScript object is garbage collected and the JS heap size is stable. According to heaptrack, suspicious allocations are occurring in napi_wrap whenever the ObjectWrap is created. I based the C++ addon on this documentation.

Clone the above repo and run:

npm install # for node-addon-api and node-gyp dependencies
npm run build # C++ build
node ./index.js

here is the loop in the minimal repro:

for (let i = 0; i < MAX_ITERS; ++i) {
  const nativeObj = NativeObj.create();
  // uncomment this and the application will not leak
  // await new Promise(setImmediate);
}

On my Ubuntu 21.10 machine with Node.js 17.5, process.memoryUsage().rss stabilizes at ~103MB
if yielding by uncommenting the await new Promise(setImmediate) line.
Otherwise it goes up until the process is killed for eating too much memory.

Is this a memory leak? It does affect a larger addon from which I created the sample loop.

Running node with --trace_gc and tracking the JavaScript heap, external, and buffer sizes demonstrate that the process memory growth is not from there, and that full mark-sweep garbage collections are occurring in parallel.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions