오브젝트를 폐기하는 방법([name])

애플리케이션에서 성능을 개선하고 메모리 누수를 방지하기 위한 중요한 한 가지는 사용되지 않는 라이브러리 개체를 폐기하는 것입니다. *three.js* 유형의 인스턴스는 생성될 때마다 일정량의 메모리를 할당하게 됩니다. 하지만 *three.js*는 특정 개체에 대해 기하학적 구조나 WebGL 관련 재질(예: 버퍼 또는 쉐이더 프로그램) 개체의 렌더링에 필요한 것입니다. 이러한 오브젝트들은 자동으로 폐기되지 않는다는 점을 주의하세요. 대신, 애플리케이션에서는 메모리 자원을 확보하기 위해 특별한 API를 사용해야 합니다. 이 가이드에서는 이 API의 사용 방법과 이와 관련해서 어떤 오브젝트가 있는지에 대한 간략한 설명을 제공해 드립니다.

기하학

기하학은 속성 집합으로 정의된 꼭짓점 정보를 표시하는데, *three.js*는 속성마다 하나의 [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer] 유형의 대상을 만들어 내부에 저장합니다. 이러한 개체는 [page:BufferGeometry.dispose]를 호출할 때만 폐기됩니다. 만약 애플리케이션에서 기하학을 더이상 사용하지 않는다면, 이 방법을 실행하여 모든 관련 자원을 폐기하세요.

재질

재질은 오브젝트가 어떻게 렌더링되는지를 정의합니다. *three.js*는 재질에 정의된 정보를 사용하여 렌더링을 위한 하나의 셰이더 프로그램을 구축합니다. 셰이더 프로그램은 해당 재질이 폐기된 후에만 삭제할 수 있습니다. 성능상의 이유로 *three.js*는 가능하다면 활용 가능한 셰이더 프로그램을 재사용하게 되어 있습니다. 따라서 셰이더 프로그램은 모든 관련된 재질들이 사라진 후에야 삭제됩니다. [page:Material.dispose]() 를 실행함으로써 재질을 폐기할 수 있습니다.

텍스쳐

재질의 폐기는 텍스쳐에 영향을 미치지 않습니다. 이들은 분리되어 있어 하나의 텍스쳐를 여러 재질로 동시에 사용할 수 있습니다. [page:Texture] 인스턴스를 만들 때마다 three.js는 내부에서 [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture] 인스턴스를 만듭니다. buffer와 비슷하게, 이 오브젝트는 [page:Texture.dispose]() 호출로만 삭제가 가능합니다.

If you use an *ImageBitmap* as the texture's data source, you have to call [link:https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap/close ImageBitmap.close]() at the application level to dispose of all CPU-side resources. An automated call of *ImageBitmap.close()* in [page:Texture.dispose]() is not possible, since the image bitmap becomes unusable, and the engine has no way of knowing if the image bitmap is used elsewhere.

렌더링 대상

[page:WebGLRenderTarget] 타입의 오브젝트는 [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture]의 인스턴스가 할당되어 있을 뿐만 아니라, [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]와 [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer] 도 할당되어, 커스텀 렌더링 목표를 실체화합니다. 이러한 오브젝트는 [page:WebGLRenderTarget.dispose]()를 실행해야만 폐기할 수 있습니다.

그밖의 것들

컨트롤러나 후기 처리 프로세스처럼 *dispose()* 메서드가 제공되어 내부 이벤트리스너나 렌더링 대상을 폐기하는 examples 폴더에서 가져온 것들이 있습니다. 일반적으로 API나 파일을 열람하고 *dispose()* 를 확인하는 것이 좋습니다. 만약 이 메서드가 존재한다면 당연히 그 메서드를 폐기 시에 사용해야 합니다.e it when cleaning things up.

FAQ

*three.js*는 왜 자동으로 오브젝트를 폐기 못하나요?

이 문제가 커뮤니티에서 여러 차례 제기돼 온 만큼 확실한 대답을 해 드려야겠습니다. 사실, *three.js*는 사용자가 만든 개체(예를 들어 기하체 또는 재질)의 라이프사이클이나 역할 범위를 알지 못하며, 이는 애플리케이션의 책임입니다. 예를 들어, 만약 하나의 재질이 현재 렌더링에 사용되고 있지 않더라도, 바로 다음 프레임에 필수적인 재질일 수 있을 것입니다. 그래서 만약 애플리케이션에서 특정 오브젝트가 삭제되어도 된다고 하면, 해당하는 *dispose()* 메서드를 통해 엔진에 알려줘야 합니다.

화면에서 mesh를 지우는 것도 geometry와 material을 폐기시키나요?

아니요, *dispose()*를 통해 명시적으로 geometry와 material을 폐기해야합니다. geometry와 material은 mesh와 마찬가지로 3D 오브젝트에서 활용할 수 있다는 점을 명심하세요.

*three.js*에서 캐시화된 오브젝트의 수를 알 수 있나요?

네, 렌더러의 그래빅 보드와 렌더링 프로세스의 통계 정보를 담고 있는 특수 속성인 [page:WebGLRenderer.info]를 통해 확인할 수 있습니다. 다른 것 보다도, 이를 통해 내부적으로 많은 텍스쳐와 기하학, 셰이더 프로그램이 저장되어 있다는 것을 알 수 있습니다. 만약 애플리케이션에서 성능 문제를 발견했다면, 바로 이 속성을 조절하여 쉽게 메모리 누출을 확인할 수 있습니다.

이미지가 아직 로딩이 안 됐는데 텍스쳐에서 *dispose()*를 해버리면 어떻게 되나요?

텍스쳐와 관련된 내부 자원은 이미지가 완전히 로딩됐을때밖에 할당이 되지 않습니다. 만약 이미지 로딩 전에 텍스쳐를 폐기해버렸다면, 아무 일도 일어나지 않을 것입니다. 아무런 자원도 할당되지 않았고 지울 것도 없기 때문입니다.

*dispose()*를 하고 나서 나중에 다시 각각의 오브젝트를 사용하면 어떻게 되나요?

삭제된 내부 자원이 엔진에서 다시 생성될 것입니다. 런타임 에러는 발생하지 않겠지만 프레임에 부정적인 영향을 미치는 것을 확인할 수 있을 것이고 특히 셰이더 프로그램을 컴파일할 때 더 두드러질 것입니다.

*three.js* 오브젝트를 앱에서 어떻게 관리해야 할까요? 언제 폐기해야되는지 어떻게 알죠?

일반적으로 이 점에 대한 명확한 해답은 없습니다. *dispose()*는 구체적인 사용 방법에 따라 적절히 활용하는 방법이 좌우됩니다. 굳이 오브젝트를 자꾸 폐기할 필요는 없다는 것을 기억해 두세요. 다양한 레벨로 구성된 게임이 좋은 예가 될 수 있을 것입니다. 레벨이 바뀌면, 폐기를 할 때입니다. 애플리케이션은 오래된 화면을 지나가면서 오래된 재질, 기하학, 텍스쳐를 모두 폐기할 수 있습니다. 앞의 장에서 언급한 바와 같이 만약 여전히 사용하고 있는 오브젝트를 폐기해도 런타임 에러를 만들지는 않을 것입니다. 단일 프레임에서 퍼포먼스가 떨어지는 정도가 가장 안 좋은 정도일 것입니다.

dispose() 사용법 예제

[example:webgl_test_memory WebGL / test / memory]
[example:webgl_test_memory2 WebGL / test / memory2]