fix: memory leak in terminal process#279172
Conversation
📬 CODENOTIFYThe following users are being notified based on files changed in this PR: @TyriarMatched files:
|
Tyriar
left a comment
There was a problem hiding this comment.
@SimonSiefke do you know why this is necessary? Disposing of a TerminalProcess is mean to release all handles to it and therefore free it and it's own references up for GC?
|
Hi @Tyriar , I believe the whole By setting But you are definitly right: When there would be no other leaks, About the promise, I'm not entirely sure. I think it's best to always set all promise properties to |
|
@SimonSiefke Do you know how I can repro this memory leak? I've tried creating and deleting terminal but that alone did not seem to show the leak on dev tool console. Are you watching the processes in some specific tool that shows the leak |
|
Hey @anthonykim1, I have this repo that I'm using: https://github.com/SimonSiefke/vscode-memory-leak-finder/ Prerequisites: Ensure you have node 24 or later installed. Test script:git clone git@github.com:SimonSiefke/vscode-memory-leak-finder.git &&
cd vscode-memory-leak-finder &&
npm ci &&
node packages/cli/bin/test.js --cwd packages/e2e --only terminal.create --runs 97 --check-leaks --measure named-function-count3 --run-skipped-tests-anyway --measure-after --inspect-ptyhost &&
cat .vscode-memory-leak-finder-results/pty-host/named-function-count3/terminal.create.jsonWith local vscode version (adjust
|
Fixes #276958
this._ptyProcessto undefined on dispose so that ptyProcess can be garbage collected on dispose.this._processStartupCompleteto undefined on dispose so that the promise can be garbage collectedBefore
When running a task 17 times, the number of various objects and functions grows each time:
{ "namedFunctionCount3": [ { "count": 40, "delta": 17, "name": "EventEmitter", "sourceLocation": "node:events:219:21" }, { "count": 39, "delta": 34, "name": "EventEmitter2", "sourceLocation": "vscode/node_modules/node-pty/lib/eventEmitter2.js:7:26", "originalName": null }, { "count": 38, "delta": 34, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/eventEmitter2.js:14:39", "originalName": null }, { "count": 32, "delta": 17, "name": "Buffer", "sourceLocation": "node:buffer:270:15" }, { "count": 24, "delta": 17, "name": "ReadableState", "sourceLocation": "node:internal/streams/readable:261:22" }, { "count": 22, "delta": 17, "name": "WritableState", "sourceLocation": "node:internal/streams/writable:303:22" }, { "count": 20, "delta": 17, "name": "ChildProcessMonitor", "sourceLocation": "vscode/out/vs/platform/terminal/node/childProcessMonitor.js:24:13", "originalLocation": "src/vs/platform/terminal/node/childProcessMonitor.ts:52:19", "originalName": "ChildProcessMonitor" }, { "count": 20, "delta": 17, "name": "StringDecoder", "sourceLocation": "node:string_decoder:80:22" }, { "count": 20, "delta": 17, "name": "UnixTerminal", "sourceLocation": "vscode/node_modules/node-pty/lib/unixTerminal.js:45:25", "originalName": null }, { "count": 20, "delta": 17, "name": "ReadStream", "sourceLocation": "node:tty:50:19" }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/terminal.js:170:30", "originalName": null }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/terminal.js:171:28", "originalName": null }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/unixTerminal.js:140:43", "originalName": null }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/unixTerminal.js:105:43", "originalName": null }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/terminal.js:91:33", "originalName": null }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/node_modules/node-pty/lib/terminal.js:92:33", "originalName": null }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "vscode/out/vs/base/common/decorators.js:59:34", "originalLocation": "src/vs/base/common/decorators.ts:83:31", "originalName": "debounce" } ], "isLeak": true }After
When running a task 17 times, there are much less leaked functions and objects:
{ "namedFunctionCount3": [ { "count": 20, "delta": 17, "name": "ChildProcessMonitor", "sourceLocation": "file:///home/simon/.cache/repos/vscode/out/vs/platform/terminal/node/childProcessMonitor.js:24:13", "originalLocation": "src/vs/platform/terminal/node/childProcessMonitor.ts:52:19", "originalName": "ChildProcessMonitor" }, { "count": 19, "delta": 17, "name": "anonymous", "sourceLocation": "file:///home/simon/.cache/repos/vscode/out/vs/base/common/decorators.js:59:34", "originalLocation": "src/vs/base/common/decorators.ts:83:31", "originalName": "debounce" } ], "isLeak": true }