Skip to content

Commit 861a67f

Browse files
committed
test: deflake test-diagnostics-channel-memory-leak
1 parent 86c7783 commit 861a67f

File tree

3 files changed

+61
-19
lines changed

3 files changed

+61
-19
lines changed

test/common/gc.js

+47
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,54 @@ async function runAndBreathe(fn, repeat, waitTime = 20) {
7575
}
7676
}
7777

78+
/**
79+
* This requires --expose-internals.
80+
* This function can be used to check if an object factory leaks or not by
81+
* iterating over the heap and count objects with the specified class
82+
* (which is checked by looking up the prototype chain).
83+
* @param {(i: number) => number} fn The factory receiving iteration count
84+
* and returning number of objects created. The return value should be
85+
* precise otherwise false negatives can be produced.
86+
* @param {Function} klass The class whose object is used to count the objects
87+
* @param {number} count Number of iterations that this check should be done
88+
* @param {number} waitTime Optional breathing time for GC.
89+
*/
90+
async function checkIfCollectableByCounting(fn, klass, count, waitTime = 20) {
91+
const { internalBinding } = require('internal/test/binding');
92+
const { countObjectsWithPrototype } = internalBinding('heap_utils');
93+
const { prototype, name } = klass;
94+
let initialCount = countObjectsWithPrototype(prototype);
95+
console.log(`Initial count of ${name}: ${initialCount}`);
96+
let totalCreated = 0;
97+
for (let i = 0; i < count; ++i) {
98+
const created = await fn(i);
99+
totalCreated += created;
100+
console.log(`#${i}: created ${created} ${name}, total ${totalCreated}`);
101+
await wait(waitTime); // give GC some breathing room.
102+
const currentCount = countObjectsWithPrototype(prototype);
103+
const collected = totalCreated - (currentCount - initialCount);
104+
console.log(`#${i}: counted ${currentCount} ${name}, collected ${collected}`);
105+
if (collected > 0 ) {
106+
console.log(`Detected ${collected} collected ${name}, finish early`);
107+
return;
108+
}
109+
}
110+
111+
await wait(waitTime); // give GC some breathing room.
112+
const currentCount = countObjectsWithPrototype(prototype);
113+
const collected = totalCreated - (currentCount - initialCount);
114+
console.log(`Last count: counted ${currentCount} ${name}, collected ${collected}`);
115+
// Some objects with the prototype can be collected.
116+
if (collected > 0) {
117+
console.log(`Detected ${collected} collected ${name}`);
118+
return;
119+
}
120+
121+
throw new Error(`${name} cannot be collected`);
122+
}
123+
78124
module.exports = {
79125
checkIfCollectable,
80126
runAndBreathe,
127+
checkIfCollectableByCounting,
81128
};

test/parallel/parallel.status

-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ prefix parallel
55
# sample-test : PASS,FLAKY
66

77
[true] # This section applies to all platforms
8-
# https://github.com/nodejs/node/pull/50327
9-
# Currently there's no reliable way to test it.
10-
test-diagnostics-channel-memory-leak: SKIP
118

129
[$system==win32]
1310
# https://github.com/nodejs/node/issues/41206
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,22 @@
1-
// Flags: --expose-gc
1+
// Flags: --expose-internals --max-old-space-size=16
22
'use strict';
33

44
// This test ensures that diagnostic channel references aren't leaked.
55

6-
require('../common');
7-
const { ok } = require('assert');
6+
const common = require('../common');
87

9-
const { subscribe, unsubscribe } = require('diagnostics_channel');
8+
const { subscribe, unsubscribe, Channel } = require('diagnostics_channel');
9+
const { checkIfCollectableByCounting } = require('../common/gc');
1010

1111
function noop() {}
1212

13-
const heapUsedBefore = process.memoryUsage().heapUsed;
14-
15-
for (let i = 0; i < 1000; i++) {
16-
subscribe(String(i), noop);
17-
unsubscribe(String(i), noop);
18-
}
19-
20-
global.gc();
21-
22-
const heapUsedAfter = process.memoryUsage().heapUsed;
23-
24-
ok(heapUsedBefore >= heapUsedAfter);
13+
const outer = 64;
14+
const inner = 256;
15+
checkIfCollectableByCounting((i) => {
16+
for (let j = 0; j < inner; j++) {
17+
const key = String(i * inner + j);
18+
subscribe(key, noop);
19+
unsubscribe(key, noop);
20+
}
21+
return inner;
22+
}, Channel, outer).then(common.mustCall());

0 commit comments

Comments
 (0)