Skip to content

Referenced Object never be recycled even if napi_delete_reference called #39915

Open
@Brooooooklyn

Description

@Brooooooklyn

Version

14.17.5

Platform

All

Subsystem

No response

What steps will reproduce the bug?

See https://github.com/Brooooooklyn/node-ref-object-leak for detail

I have a js function in native side, which accept a JsBuffer:

#[js_function(1)]
fn ref_buffer(ctx: napi::CallContext) -> napi::Result<napi::JsNumber> {
    let buffer = ctx.get::<napi::JsBuffer>(0)?;
    let ref_buffer = buffer.into_ref()?;
    let ref_count = ref_buffer.unref(ctx.env.clone())?;
    ctx.env.create_uint32(ref_count)
}

The napi_create_reference, napi_reference_unref and napi_delete_reference are called in this function.

In the JavaScript side:

const { readFileSync } = require('fs')

const { refBuffer } = require('./index.node')
const { displayMemoryUsageFromNode } = require('./util')

const BigBuffer = readFileSync('yarn.lock')

const initial = process.memoryUsage()

async function main() {
  for (const [i] of Array.from({ length: 10000000 }).entries()) {
    let refCount = refBuffer(BigBuffer)
    if (refCount) {
      throw new Error(`refCount should be 0, but got ${refCount}`)
    }
    if (i % 1000000 === 0) {
      await sleep() // Async function to give GC a chance
      if (typeof global.gc === 'function') {
        global.gc()
      }
      displayMemoryUsageFromNode(initial)
    }
  }
}

function sleep() {
  return new Promise((resolve) => {
    setTimeout(resolve, 1000)
  })
}

main()

We can see the memory is growing:

╔══════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss      │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟──────────┼───────────┼──────────┼──────────┼──────────────╢
║ +80.1 MB │ +80 MB    │ +80 MB   │ +40 B    │  0 B         ║
╚══════════╧═══════════╧══════════╧══════════╧══════════════╝

╔═════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss     │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟─────────┼───────────┼──────────┼──────────┼──────────────╢
║ +250 MB │ +85.3 MB  │ +79 MB   │ -170 kB  │ -162 kB      ║
╚═════════╧═══════════╧══════════╧══════════╧══════════════╝

╔═════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss     │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟─────────┼───────────┼──────────┼──────────┼──────────────╢
║ +414 MB │ +85.3 MB  │ +79.7 MB │ -170 kB  │ -162 kB      ║
╚═════════╧═══════════╧══════════╧══════════╧══════════════╝

╔═════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss     │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟─────────┼───────────┼──────────┼──────────┼──────────────╢
║ +576 MB │ +85.3 MB  │ +79.3 MB │ -170 kB  │ -162 kB      ║
╚═════════╧═══════════╧══════════╧══════════╧══════════════╝

╔═════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss     │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟─────────┼───────────┼──────────┼──────────┼──────────────╢
║ +739 MB │ +85.3 MB  │ +79.1 MB │ -170 kB  │ -162 kB      ║
╚═════════╧═══════════╧══════════╧══════════╧══════════════╝

╔═════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss     │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟─────────┼───────────┼──────────┼──────────┼──────────────╢
║ +902 MB │ +85.3 MB  │ +79 MB   │ -170 kB  │ -162 kB      ║
╚═════════╧═══════════╧══════════╧══════════╧══════════════╝

╔══════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss      │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟──────────┼───────────┼──────────┼──────────┼──────────────╢
║ +1.06 GB │ +85.3 MB  │ +79 MB   │ -170 kB  │ -162 kB      ║
╚══════════╧═══════════╧══════════╧══════════╧══════════════╝

╔══════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss      │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟──────────┼───────────┼──────────┼──────────┼──────────────╢
║ +1.23 GB │ +85.3 MB  │ +79.1 MB │ -170 kB  │ -162 kB      ║
╚══════════╧═══════════╧══════════╧══════════╧══════════════╝

╔══════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss      │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟──────────┼───────────┼──────────┼──────────┼──────────────╢
║ +1.39 GB │ +85.3 MB  │ +79 MB   │ -170 kB  │ -162 kB      ║
╚══════════╧═══════════╧══════════╧══════════╧══════════════╝

╔══════════╤═══════════╤══════════╤══════════╤══════════════╗
║ rss      │ heapTotal │ heapUsed │ external │ arrayBuffers ║
╟──────────┼───────────┼──────────┼──────────┼──────────────╢
║ +1.55 GB │ +85.3 MB  │ +79 MB   │ -170 kB  │ -162 kB      ║
╚══════════╧═══════════╧══════════╧══════════╧══════════════╝

How often does it reproduce? Is there a required condition?

Always

What is the expected behavior?

Buffer is deallocated

What do you see instead?

Buffer is never been deallocated

Additional information

Brooooooklyn/snappy#25

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    node-apiIssues and PRs related to the Node-API.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions