monaco-editor
monaco-editor copied to clipboard
[Bug] Memory leaking when disposing Diff editor
Reproducible in vscode.dev or in VS Code Desktop?
- [X] Not reproducible in vscode.dev or VS Code Desktop
Reproducible in the monaco editor playground?
- [X] Not reproducible in the monaco editor playground
Monaco Editor Playground Link
No response
Monaco Editor Playground Code
No response
Reproduction Steps
I wrote a small application demonstrating the issue: You can find it on the following link: https://zd9n67.csb.app/ Code: https://codesandbox.io/p/sandbox/react-typescript-forked-zd9n67
Actual (Problematic) Behavior
Diff editor does not dispose correctly after being removed from the dom. The regular editor component does not have this issue.
Initial load
Second memory snapshot
Third memory snapshot
Fourth memory snapshot
The memory constantly grows as the diff editor is not properly disposed of. Form my investigation I could see that the Emitter and InteractionEmitter are constantly growing without being disposed in the monaco-editor/esm/vs/editor/browser/widget/codeEditor/codeEditorWidget.js file.
Also a lot of detached canvas dom elements like:
<canvas class="original diffOverviewRuler" ...
Expected Behavior
Diff editor gets removed properly and does not cause a memory leak.
Additional Context
We started observing the issue in the 0.44.0 version of monaco-editor as the earlier versions don't seem to have this problem. The example is for the latest version 0.51.0
Probably would be a good idea to write a unit test in the monaco editor library to test against memory leaks in the future?
I've submitted a fix in the vscode repo in case anyone needs to fix this in their codebase.
I'm not sure if this is directly related to a bug, but I encountered a strange behavior when switching from a DiffEditor to a regular Editor. After disposing a DiffEditor and then creating a regular Editor, the arrow keys (← →) start moving the cursor two characters instead of one.
Here's a minimal example to reproduce the issue. Please try it in the Monaco Playground:
let editor = null;
let diffEditor = null;
function disposeEditors() {
monaco.editor.getEditors().forEach(e => e.dispose());
monaco.editor.getModels().forEach(m => m.dispose());
editor = null;
diffEditor = null;
}
function initializeEditor(content = "") {
require(['vs/editor/editor.main'], function () {
disposeEditors();
const container = document.getElementById('container');
container.innerHTML = "";
editor = monaco.editor.create(container, {
value: content,
});
});
}
function initializeDiffEditor(originalContent, modifiedContent) {
require(['vs/editor/editor.main'], function () {
disposeEditors();
const container = document.getElementById('container');
container.innerHTML = "";
diffEditor = monaco.editor.createDiffEditor(container, {
});
const originalModel = monaco.editor.createModel(originalContent, 'plaintext');
const modifiedModel = monaco.editor.createModel(modifiedContent, 'plaintext');
diffEditor.setModel({ original: originalModel, modified: modifiedModel });
});
}
initializeEditor("AABBAABB");
initializeDiffEditor("AAAA", "BBBB")
initializeEditor("AABBAABB");
@samirzubi-db, I have checked. Only by adding this._codeEditorService.removeDiffEditor(this);this._onDidDispose.fire();super.dispose() in diffEditorWidget.js- will not work, What I see here in abstractCodeEditorService.js under Services, There is no implementation for removeDiffEditor, I have added removeDiffEditor(editor) { if (delete this._diffEditors[editor.getId()]) { this._onDiffEditorRemove.fire(editor); } }
Now, I has started working. I am using monaco editor latest version.
I'm not sure if this is directly related to a bug, but I encountered a strange behavior when switching from a DiffEditor to a regular Editor. After disposing a DiffEditor and then creating a regular Editor, the arrow keys (← →) start moving the cursor two characters instead of one.
@Osg-Junue, I came across the same behavior. What I found is that in accessibleDiffViewer keys are attached as events to the root DOM node. And it seems it is not cleared well when disposing. When I removed some event listeners manually in DevTools, it helped.
I still see some leak on the latest preview 0.55.0-dev-20251105 , using the codesandbox example linked above after 2000 iterations: