유니티의 데모가 WebGPU와 WebAssembly의 결합 가능성을 증명한 이후, 웹 개발 생태계는 새로운 르네상스를 맞이하는 듯했다. 이번에는 웹 기반 3D CAD 소프트웨어를 만드는 한 유망한 스타트업에서 승전보를 울렸다.
그들은 자사의 블로그에 ‘WebGPU를 통한 10배의 성능 향상’이라는 제목의 글을 게시했다. 수십만 개의 부품으로 이루어진 복잡한 기계 모델을 브라우저에서 실시간으로 조작하는 영상은 경이로움 그 자체였다. 그들은 글의 마지막에 Dawn 팀에게 특별한 감사를 표했다.
성공적인 적용 사례는 Dawn 팀에게 큰 자부심을 안겨주었다. 하지만 몇 주 후, 드미트리는 그 스타트업의 CTO로부터 한 통의 비공개 메일을 받았다. 메일의 내용은 블로그 글과는 전혀 다른, 다급함과 곤혹스러움으로 가득 차 있었다.
“드미트리, 저희는 지금 심각한 문제에 부딪혔습니다. 저희 앱은 초기 몇 분간은 환상적인 성능을 보여주지만, 사용 시간이 30분을 넘어가면 점차 느려지기 시작하고, 결국에는 브라우저 탭이 ‘메모리 부족’ 오류와 함께 크래시됩니다. 저희는 자바스크립트 메모리 누수를 잡기 위해 모든 노력을 기울였지만, 아무것도 찾지 못했습니다. 혹시 WebGPU나 Dawn 내부에 장시간 실행 시 발생하는 메모리 누수가 있는 것은 아닌지 검토를 부탁드립니다.”
그 메일은 Dawn 팀에 미묘한 파장을 일으켰다. 자신들의 코드에 결함이 있을 수 있다는 의심은 언제나 불쾌한 일이었다.
“그럴 리 없어. 우리는 수개월간의 베타 테스트를 거쳤다고.”
벤이 자신 있게 말했다.
드미트리는 그의 말을 막지 않았다. 대신, 그는 침착하게 지시했다.
“추측은 금물이다. 직접 확인해봐야지. 그들의 애플리케이션을 우리 내부의 메모리 프로파일링 환경에서 장시간 실행해 보게. Dawn이 할당한 C++ 메모리가 시간에 따라 어떻게 변하는지 추적해.”
팀은 즉시 테스트에 착수했다. 그들은 문제의 CAD 앱을 특수 빌드된 크롬에서 몇 시간 동안 구동시키며, Dawn 엔진의 모든 메모리 할당과 해제를 1밀리초 단위로 기록했다.
결과는 그들의 예상을 확증해주었다.
“문제없습니다. Dawn의 메모리 사용량은 완전히 안정적입니다. 일정한 수준 이상으로 전혀 증가하지 않아요.”
카이가 보고했다. Dawn의 코드는 결백했다.
안도감도 잠시, 드미트리의 표정은 더욱 심각해졌다.
“그렇다면 문제는 더 심각한 거야.”
팀원들이 그를 바라보았다.
“우리에게 버그가 있는 거라면, 우리가 고치면 그만이야. 하지만 우리에게 버그가 없다면, 그건 개발자들이 우리 API를 ‘잘못 사용’하고 있다는 뜻이지. 그리고 그 잘못된 사용법이 왜 그렇게 쉽게 발생하는지를 우리가 이해하지 못하면, 이런 문제는 앞으로 계속해서 터져 나올 거야.”
그는 다시 CAD 앱을 실행했다. 이번에는 크롬 개발자 도구가 아닌, GPU 제조사에서 제공하는 저수준 그래픽 디버거를 연결했다. 그는 이제 브라우저의 메모리가 아닌, GPU 하드웨어에 직접 할당된 ‘비디오 메모리’의 상태를 들여다보기 시작했다.
그리고 그는 문제의 원흉을 발견했다.
GPU 메모리 뷰어에는 수십만 개의 작은 버퍼와 텍스처 객체들이 빼곡히 들어차 있었다. 마치 쓰레기 하치장처럼, 더 이상 사용되지 않는 자원들이 버려지지 않고 계속해서 쌓여가고 있었다.
“이럴 수가… 그들은 자원을 해제하지 않고 있었어.”
문제의 핵심은 WebGPU의 자원 관리 철학에 있었다.
자바스크립트에서는 개발자가 객체에 대한 참조를 없애면, 가비지 컬렉터(Garbage Collector)가 알아서 메모리를 청소해준다. 하지만 GPU 자원은 달랐다. 개발자가 buffer.destroy()
나 texture.destroy()
같은 함수를 ‘명시적으로’ 호출해주지 않으면, 자바스크립트 객체는 사라져도 GPU 메모리 공간은 그대로 점유된 채로 남았다. WebGPU는 성능을 위해 자원 관리에 대한 책임을 전적으로 개발자에게 넘겼던 것이다.
그 스타트업 개발자들은 이 사실을 간과했다. 그들은 WebGL 시절의 습관대로, 참조만 없애면 모든 것이 해결될 거라 생각했던 것이다. 보이지 않는 ‘GPU 메모리 빚’이 계속해서 쌓여가다, 마침내 시스템의 한계를 넘어서자 탭이 붕괴한 것이었다.
드미트리는 스타트업 CTO에게 분석 결과를 상세히 설명해주었다. 그들은 자신들의 실수를 깨닫고 즉시 코드 수정에 들어갔다.
하지만 드미트리는 이 사건이 일회성 해프닝으로 끝나지 않을 것임을 알았다. 이것은 생태계 전체에 보내는 경고였다. 그는 팀원들을 모았다.
“우리는 개발자들에게 더 나은 나침반을 줘야 해. 그들이 보이지 않는 빚을 지고 있다는 사실을 스스로 깨닫게 해줘야 한다.”
그는 새로운 내부 프로젝트를 제안했다.
“크롬 개발자 도구에 ‘WebGPU’ 패널을 새로 만듭시다. 그 패널에는 현재 페이지에서 사용 중인 모든 GPU 버퍼, 텍스처, 파이프라인의 목록이 실시간으로 표시되어야 합니다. 그리고 만약 자바스크립트 객체는 사라졌는데 destroy()
가 호출되지 않은 ‘유령 자원’이 있다면, 그 목록에 붉은색 경고 표시를 띄워주는 겁니다.”
그것은 단순한 디버깅 기능을 넘어선, 개발자들을 올바른 길로 이끄는 교육적인 도구였다. API를 만드는 것을 넘어, 그 API를 둘러싼 생태계 전체의 건강을 책임지는 것. 그것이 플랫폼을 소유한 자의 숙명임을 드미트리는 다시 한번 무겁게 깨닫고 있었다.