Change:
<ins> /*--------------------------------------------------------------------------------------------- *  Copyright (c) Microsoft Corporation. All rights reserved. *  Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ //@ts-check // note: we use a fork here since we can't make a worker from the renderer process const { fork } = require('child_process'); const workerData = process.env.SNAPSHOT_WORKER_DATA; const fs = require('fs'); const { pathToFileURL } = require('url'); if (!workerData) { const { join } = require('path'); const { tmpdir } = require('os'); exports.takeSnapshotAndCountClasses = async (/** @type string */currentTest, /** @type string[] */ classes) => { const cleanTitle = currentTest.replace(/[^w]+/g, '-'); const file = join(tmpdir(), `vscode-test-snap-${cleanTitle}.heapsnapshot`); if (typeof process.takeHeapSnapshot !== 'function') { // node.js: const inspector = require('inspector'); const session = new inspector.Session(); session.connect(); const fd = fs.openSync(file, 'w'); await new Promise((resolve, reject) => { session.on('HeapProfiler.addHeapSnapshotChunk', (m) => { fs.writeSync(fd, m.params.chunk); }); session.post('HeapProfiler.takeHeapSnapshot', null, (err) => { session.disconnect(); fs.closeSync(fd); if (err) { reject(err); } else { resolve(); } }); }); } else { // electron exposes this nice method for us: process.takeHeapSnapshot(file); } const worker = fork(__filename, { env: { ...process.env, SNAPSHOT_WORKER_DATA: JSON.stringify({ path: file, classes, }) } }); const promise = new Promise((resolve, reject) => { worker.on('message', (/** @type any */msg) => { if ('err' in msg) { reject(new Error(msg.err)); } else { resolve(msg.counts); } worker.kill(); }); }); return { done: promise, file: pathToFileURL(file) }; }; } else { const { path, classes } = JSON.parse(workerData); const { decode_bytes } = require('@vscode/v8-heap-parser'); fs.promises.readFile(path) .then(buf => decode_bytes(buf)) .then(graph => graph.get_class_counts(classes)) .then( counts => process.send({ counts: Array.from(counts) }), err => process.send({ err: String(err.stack || err) }) ); } </ins>

Discussion:
<!-- Do Not Delete This! featurerequesttemplate --<!-- Please read our Rules of Conduct: --<!-- Please search existing issues to avoid creating duplicates. --<!-- Describe the feature you'd like. --Currently we are manually hunting down memory leaks through Dev Tools. For some areas/components (e.g., notebook), this even needs to be done repeatedly. It would be helpful if we can capture the memory snapshots in CI and write some queries against the snapshot to analyze if there is any potential leaks. A typical manual memory leak analysis for notebook Setup Open OSS Open notebook document A Open notebook document B Close both notebook documents Open Dev Tools, take a heap snapshot Search object, there should be none Search object, there should be none Search object, there should not be more than one (the editor group still holds a reference to the last editor) ! cc
The dev tools also show how an object is leaked, we could analyze the dependencies tree and figure out who is the "culprit"
would be a good API for CI use case on desktop to capture from any non-sandboxed process (Main, Utility - Ext Host, Shared Process, Pty Agent) embedding V8 without using external CDP calls. In the case of sandboxed render process, prefer
I find this topic super interesting as well! I have a prototype project that tries to find memory leaks by looking for leaking event listeners. In the screencast, the event listener count increases from 1175 to 1206 which indicates that there might be a memory leak when opening and closing a notebook editor. The project is in the early phases and in the future I'm hoping to display more detailed output for the event listeners as well as making the tests less flaky. (sorry if I'm interrupting the discussion. I'm hoping that perhaps this could be useful for you)