수 백장의 dicom파일을 사용자가 업로드 할 때, 메모리 사용량이 99%를 넘어가면서 error가 발생하는 문제가 있었다.
vtk라이브러리를 통해 dicom파일에서 ct 이미지들을 3d 볼륨 랜더링으로 구현하고자 하는데, 처리할 파일의 크기에 따라 랜더링 여부가 결정되는건 말이 안되는 일이었다.
따라서, 현재는 파일의 갯수나 사이즈와 상관없이 사용자에게 안정적으로 랜더링을 약속할 수 있도록 방안을 찾고있다.
일단, 소프트 웨어적으로 할 수 있는 부분을 찾아보자면 당연한 이야기겠지만 vtk lib에 대한 이해가 좀 필요한 것 같다.
단순히 delete()
를 호출해주고 객체를 null로 초기화 해주는 작업이긴 하지만 상당히 중요한 포인트라고 생각한다.
- 처음: 450개의 dicom CT file upload → 5,144.5MB 사용
- 변경: 796개의 dicom CT file upload Change → 6,592.8MB 사용
- 다시 변경: 450개의 dicom CT file로 전환 → 2,790.9MB 사용
즉, 처음 상태(5,144.5MB)보다 다시 450개로 전환한 후 메모리 사용량이 크게 감소(2,790.9MB)한 상태임.
vtk 라이브러리는 파일 체인지 시 초기화 및 가비지 컬렉션을 별도로 설정하지 않으면 데이터를 임시로 쌓아둔다. 왜냐하면, ‘WebGL 컨텍스트와 직접 상호 작용하는 저 수준 그래픽스 라이브러리’ 이기 때문에 javaScript의 일반적인 가비지 컬렉션만으로는 메모리가 완전히 해제되지 않는다.
‘VTK.js는 WebGL 컨텍스트와 직접 상호 작용하는 저 수준 그래픽스 라이브러리’라는 의미는,
[상위 레벨]
브라우저 JavaScript (일반적인 웹 개발에서 사용하는 코드)
↓
VTK.js (3D 그래픽스 처리를 위한 중간 계층)
↓
WebGL (GPU와 직접 통신하는 그래픽스 API)
↓
GPU 하드웨어
[하위 레벨]
이 과정에서 사용된 GPU 리소스는 명시적으로 해제해야 한다.
메모리를 정리하지 않으면 WebGL 리소스가 계속 남아있고, GPU 메모리 누수가 발생한다. 또한 시스템 메모리에서도 VTK 객체들이 계속 유지되는 상태가 된다. 따라서, VTK.js객체를 사용할 때는 아래와 같은 처리 단계가 필요하다.
1. `.delete()` 메서드를 명시적으로 호출
2. 렌더러에서 제거
3. `mapper`, `volume` 데이터를 모두 null로 정리
이 세 단계를 모두 수행해야 메모리가 제대로 해제된다.
// 예시 코드
function cleanupExistingVolume() {
if (renderer && volume) {
try {
renderer.removeVolume(volume)
volumeMapper?.delete()
volume?.delete()
// 렌더러 초기화
renderer.resetCamera()
renderWindow?.render()
} catch (error) {
console.error('Cleanup error:', error)
} finally {
volumeMapper = null
volume = null
}
}
}