From 5d93002a14d506d202ce0fc93584022ee54ccc12 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Tue, 14 Jan 2025 13:35:54 +0100 Subject: [PATCH] test: add maxCount and gcOptions to gcUntil() PR-URL: https://github.com/nodejs/node/pull/56522 Reviewed-By: James M Snell Reviewed-By: Chengzhong Wu --- test/common/gc.js | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/test/common/gc.js b/test/common/gc.js index 82cc4c79edc3dd..87625068c2cbca 100644 --- a/test/common/gc.js +++ b/test/common/gc.js @@ -3,6 +3,8 @@ const wait = require('timers/promises').setTimeout; const assert = require('assert'); const common = require('../common'); +// TODO(joyeecheung): rewrite checkIfCollectable to use this too. +const { setImmediate: setImmediatePromisified } = require('timers/promises'); const gcTrackerMap = new WeakMap(); const gcTrackerTag = 'NODE_TEST_COMMON_GC_TRACKER'; @@ -40,32 +42,26 @@ function onGC(obj, gcListener) { /** * Repeatedly triggers garbage collection until a specified condition is met or a maximum number of attempts is reached. + * This utillity must be run in a Node.js instance that enables --expose-gc. * @param {string|Function} [name] - Optional name, used in the rejection message if the condition is not met. * @param {Function} condition - A function that returns true when the desired condition is met. + * @param {number} maxCount - Maximum number of garbage collections that should be tried. + * @param {object} gcOptions - Options to pass into the global gc() function. * @returns {Promise} A promise that resolves when the condition is met, or rejects after 10 failed attempts. */ -function gcUntil(name, condition) { - if (typeof name === 'function') { - condition = name; - name = undefined; - } - return new Promise((resolve, reject) => { - let count = 0; - function gcAndCheck() { - setImmediate(() => { - count++; - global.gc(); - if (condition()) { - resolve(); - } else if (count < 10) { - gcAndCheck(); - } else { - reject(name === undefined ? undefined : 'Test ' + name + ' failed'); - } - }); +async function gcUntil(name, condition, maxCount = 10, gcOptions) { + for (let count = 0; count < maxCount; ++count) { + await setImmediatePromisified(); + if (gcOptions) { + await global.gc(gcOptions); + } else { + await global.gc(); // Passing in undefined is not the same as empty. } - gcAndCheck(); - }); + if (condition()) { + return; + } + } + throw new Error(`Test ${name} failed`); } // This function can be used to check if an object factor leaks or not,