Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions test/js/node/net/net-mongodb-pattern-leak.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,11 @@ async function command(sock: net.Socket, messages: Transform, body: Buffer) {

function snapshot() {
Bun.gc(true);
const t = heapStats().objectTypeCounts;
const hs = heapStats();
const t = hs.objectTypeCounts;
return {
rss: process.memoryUsage.rss(),
heapSize: hs.heapSize,
Timeout: t.Timeout || 0,
Promise: t.Promise || 0,
AsyncGenerator: t.AsyncGenerator || 0,
Expand All @@ -172,10 +174,10 @@ describe.each([

try {
const body = Buffer.alloc(256, 0x61);
const ITER = isDebug || isASAN ? 2_000 : 5_000;
const ITER = isDebug || isASAN ? 1_500 : 5_000;

// Run the workload twice. Round 1 absorbs JIT, root-CA load and allocator
// pool growth; round 2 is steady-state. We assert on round-2 vs round-1.
// Round 0 absorbs JIT tier-up, root-CA load and allocator pool growth;
// rounds 1 and 2 are steady-state. We assert on round-2 vs round-1.
const round = async () => {
for (let i = 0; i < ITER; i++) {
const reply = await command(sock, messages, body);
Expand All @@ -185,6 +187,7 @@ describe.each([
return snapshot();
};

await round(); // warmup; JIT tier-up is not reliably done after one round
const after1 = await round();
const after2 = await round();

Expand All @@ -196,14 +199,17 @@ describe.each([
expect(after2.AsyncGenerator - after1.AsyncGenerator).toBeLessThanOrEqual(2);
expect(after2.Promise - after1.Promise).toBeLessThanOrEqual(10);
expect(after2.Function - after1.Function).toBeLessThanOrEqual(20);
// vm.heap.size() after a sync full GC: live-cell bytes, not affected by
// allocator/JIT. Observed r2-r1 range -38..+8 KB; a listener leak is ~56 MB.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
expect(after2.heapSize - after1.heapSize).toBeLessThan(256 * 1024);

// The Transform must not have accumulated listeners (onData removes its
// pair on .return(); a missed cleanup would grow this by ITER).
expect(messages.listenerCount("data")).toBe(0);
expect(messages.listenerCount("error")).toBeLessThanOrEqual(1);

// RSS round-2 vs round-1: weak signal (mimalloc segment noise) but
// catches anything egregious that heapStats can't see.
// RSS at steady state: weak signal (mimalloc segment noise) but catches
// anything egregious that heapStats can't see.
const rssBound = isASAN || isDebug ? 32 * 1024 * 1024 : 8 * 1024 * 1024;
expect(after2.rss - after1.rss).toBeLessThan(rssBound);
} finally {
Expand Down
Loading