[Open WebUI] PanZoom 인스턴스 메모리 누수를 PanzoomContainer 컴포넌트로 통합 해결
PR 링크: open-webui/open-webui#23236 상태: Merged | 변경: +72 / -109
들어가며
Open WebUI에서 이미지 프리뷰, SVG, 오피스 슬라이드 등 여러 곳에서 panzoom 라이브러리를 사용합니다. 각 컴포넌트가 독립적으로 panzoom 인스턴스를 생성하고 onDestroy에서 dispose()를 호출하는 패턴이 반복되었는데, 일부 컴포넌트에서 dispose가 누락되거나 reactive 블록($:)에서 인스턴스를 재생성하면서 이전 인스턴스가 정리되지 않는 메모리 누수가 발생했습니다.
핵심 코드 분석
Before: 각 컴포넌트에서 개별 관리
<!-- ImagePreview.svelte -->
<script>
let instance: PanZoom;
$: if (sceneElement) {
// reactive 블록에서 매번 새 인스턴스 생성 - 이전 것은 dispose 안 됨!
instance = panzoom(sceneElement, { bounds: true, ... });
}
// onDestroy가 없거나 불완전
</script>
<div bind:this={sceneElement}>
<img {src} {alt} />
</div>
After: PanzoomContainer로 통합
<!-- PanzoomContainer.svelte -->
<script>
import { onMount } from 'svelte';
import panzoom, { type PanZoom, type PanZoomOptions } from 'panzoom';
let containerElement: HTMLElement;
let instance: PanZoom | undefined;
export const reset = () => {
instance?.moveTo(0, 0);
instance?.zoomAbs(0, 0, 1);
};
onMount(() => {
const localInstance = panzoom(containerElement, { ...defaultOpts, ...options });
instance = localInstance;
return () => { localInstance.dispose(); }; // cleanup 보장
});
</script>
<div bind:this={containerElement} class={className}>
<slot />
</div>
<!-- 사용하는 쪽 -->
<PanzoomContainer bind:this={panzoomRef} className="...">
<img {src} {alt} />
</PanzoomContainer>
왜 이게 좋은가
- dispose 보장:
onMount의 반환 함수로 cleanup을 처리하므로 컴포넌트 해제 시 panzoom 인스턴스가 반드시 정리된다. - 코드 중복 제거: FilePreview, FileItemModal, ImagePreview, SVGPanZoom 4개 컴포넌트의 반복 로직을 하나로 통합했다.
- reactive 블록 재생성 문제 해결:
$:블록 대신onMount를 사용하여 인스턴스 중복 생성이 원천적으로 불가능하다.
참고 자료
관련 포스트
PR Analysis 의 다른글
- 이전글 [gradio] Gradio SSE 라우트의 폴링 제거를 통한 성능 최적화
- 현재글 : [Open WebUI] PanZoom 인스턴스 메모리 누수를 PanzoomContainer 컴포넌트로 통합 해결
- 다음글 [Ultralytics] v8.4.28 — autobatch를 데이터셋 크기로 제한하여 소규모 데이터셋 학습 안정화
댓글