weak-napi: N-API Weak References
weak-napi is a Node.js module that provides functionality for creating weak references to JavaScript objects and registering callbacks that execute upon an object's garbage collection. It exposes the underlying V8 engine's GC tracking features, which are otherwise inaccessible from JavaScript. The current stable version is 2.0.2, with a release cadence primarily focused on N-API compatibility and stability. A key differentiator from its predecessor, `node-weak`, is its utilization of N-API, eliminating the need for recompilation across different Node.js versions and improving the robustness of GC callbacks to prevent crashes. It requires Node.js 6 or newer due to its reliance on Proxy objects for comprehensive property handling, and notably does not support the `isNearDeath()` API. This module is commonly employed for debugging memory leaks and understanding the lifecycle of objects within Node.js applications.
Common errors
-
Error: The module 'weak-napi.node' was compiled against a different Node.js version. This version of Node.js cannot load this module.
cause The native addon was compiled for a different Node.js major version than the one currently running the application.fixRun `npm rebuild weak-napi` in your project directory to recompile the native module against your current Node.js version. -
TypeError: Object.getOwnPropertyDescriptors called on non-object
cause This error or similar Proxy-related errors occur when `weak-napi` is run on a Node.js version older than 6, which lacks full support for JavaScript Proxy objects.fixUpgrade your Node.js environment to version 6 or newer. Using a recent LTS version is highly recommended. -
GC callback function not firing, or objects never appear to be garbage collected.
cause A strong reference to the weakly-referenced object still exists somewhere in the application's memory, preventing the garbage collector from reclaiming it. A common culprit is defining the callback in a closure that captures the object.fixReview your code to ensure no strong references remain to the object after `obj = null;`. Pay close attention to the scope where your GC callback is defined, ensuring it doesn't close over the `obj` variable itself. -
Error: Cannot find module 'weak-napi' or Error: The specified module could not be found.
cause The `weak-napi` native addon failed to compile during installation, or its compiled binary (`.node` file) is missing or corrupted.fixCheck the `npm install` logs for any compilation errors. Ensure you have required build tools (like `node-gyp` and a C++ compiler) installed. Then run `npm rebuild weak-napi` to attempt recompilation.
Warnings
- breaking The `isNearDeath()` method is explicitly not supported and will always return `false`. Code relying on this method's prior functionality in `node-weak` will break or behave unexpectedly.
- gotcha Defining the GC callback function within the same scope as the object being weakly referenced can unintentionally create a strong reference to the object, preventing it from ever being garbage collected. This leads to memory leaks.
- breaking `weak-napi` requires Node.js version 6 or higher due to its internal use of JavaScript `Proxy` objects. Running on older Node.js versions will result in runtime errors related to unsupported language features.
- gotcha Although `weak-napi` uses N-API (which reduces recompilation issues), it is still a native Node.js addon. Compilation can fail if your system lacks necessary build tools (e.g., C++ compilers, Python, `node-gyp`).
Install
-
npm install weak-napi -
yarn add weak-napi -
pnpm add weak-napi
Imports
- weak (CJS)
const weak = require('weak-napi') - weak (ESM)
import { weak } from 'weak-napi'import weak from 'weak-napi'
Quickstart
var weak = require('weak-napi');
// We will monitor this object and invoke 'cleanup' after it's garbage collected
let obj = {
id: 'my-object',
data: Array(1000).fill('some data string') // Make it large enough to be GC'd
};
// Define the cleanup callback at a high scope to avoid strong references
function cleanupCallback() {
console.log('"obj" with ID ' + this.id + ' has been garbage collected!');
}
// Create a weak reference to obj with the cleanup callback
// Note: `this` inside the callback refers to the EventEmitter instance returned by `weak()`.
const ref = weak(obj, cleanupCallback);
ref.id = obj.id; // Store ID on the ref for logging in callback
console.log('Weak reference created. Initial obj.id:', obj.id);
// Dereference the object to allow it to be garbage collected
obj = null;
console.log('Original object reference cleared. Waiting for GC...');
// In a real scenario, you'd let your application run.
// For demonstration, we might try to force GC, but it's not reliable or recommended.
// Global.gc is usually not available unless explicitly enabled with --expose-gc.
// If process.env.EXPOSE_GC is set, you can try to call it:
if (typeof global.gc === 'function') {
console.log('Attempting to force garbage collection...');
global.gc();
global.gc(); // Call twice for better chances
} else {
console.log('Run Node.js with --expose-gc flag to see immediate callback execution via global.gc().');
console.log('Otherwise, the callback will eventually fire when V8 decides to run GC naturally.');
}
// Keep the process alive for a bit to allow GC to run naturally
setTimeout(() => {
console.log('Process ending. If GC ran, you should have seen the callback message.');
}, 500);