[Open WebUI] CodeEditor에서 EditorView 미해제로 인한 메모리 누수 수정
PR 링크: open-webui/open-webui#22110 상태: Merged | 변경: +36 / -28
들어가며
Open WebUI의 CodeEditor 컴포넌트에서 CodeMirror의 EditorView 인스턴스가 컴포넌트 해제 시 destroy()되지 않아 메모리 누수가 발생하고 있었습니다. EditorView는 내부적으로 DOMObserver를 유지하고 DOM 참조를 보유하므로, 명시적으로 해제하지 않으면 가비지 컬렉터가 수거할 수 없습니다. 또한 매 컴포넌트 인스턴스마다 languages 배열에 HCL, Elixir, Matlab 언어를 중복 등록하는 문제도 있었습니다.
핵심 코드 분석
Before: EditorView 미해제 + 인스턴스별 언어 등록
<script>
let codeEditor;
// 매 컴포넌트 인스턴스마다 languages 배열에 중복 추가
languages.push(LanguageDescription.of({
name: 'HCL', extensions: ['hcl', 'tf'],
load() { return import('codemirror-lang-hcl').then((m) => m.hcl()); }
}));
onMount(() => {
return () => {
observer.disconnect();
document.removeEventListener('keydown', keydownHandler);
// EditorView.destroy() 호출 없음 - 메모리 누수!
};
});
</script>
After: EditorView destroy + 모듈 수준 언어 등록
// src/lib/utils/codemirror.ts - 모듈 수준에서 한 번만 실행
import { LanguageDescription } from '@codemirror/language';
import { languages } from '@codemirror/language-data';
languages.push(
LanguageDescription.of({ name: 'HCL', ... })
);
languages.push(
LanguageDescription.of({ name: 'Elixir', ... })
);
<script>
import '$lib/utils/codemirror';
let codeEditor: EditorView | null = null;
onMount(() => {
return () => {
observer.disconnect();
document.removeEventListener('keydown', keydownHandler);
if (codeEditor) {
codeEditor.destroy();
codeEditor = null;
}
};
});
</script>
왜 이게 좋은가
- 메모리 누수 수정:
EditorView.destroy()는 내부DOMObserver를 해제하고 DOM 참조를 정리합니다. 채팅 메시지를 탐색하며 여러 코드 에디터를 마운트/언마운트할 때 메모리가 지속적으로 증가하던 문제가 해결됩니다. - 중복 등록 방지: 언어 등록을 별도 모듈(
codemirror.ts)로 분리하여 ES 모듈 시스템이 자연스럽게 한 번만 실행되도록 합니다. - 타입 안전성:
codeEditor에EditorView | null타입을 명시하고 옵셔널 체이닝(?.)을 사용합니다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [Open WebUI] UserMessage에서 JSON 직렬화 대신 structuredClone과 빠른 경로 비교 적용
- 현재글 : [Open WebUI] CodeEditor에서 EditorView 미해제로 인한 메모리 누수 수정
- 다음글 [Open WebUI] requestAnimationFrame으로 스트리밍 중 getContents() 디바운싱
댓글