| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- <!DOCTYPE html><html lang="en"><head>
- <meta charset="utf-8">
- <title>How to dispose of Objects</title>
- <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
- <meta name="twitter:card" content="summary_large_image">
- <meta name="twitter:site" content="@threejs">
- <meta name="twitter:title" content="Three.js – How to dispose of Objects">
- <meta property="og:image" content="https://threejs.org/files/share.png">
- <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
- <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
- <link rel="stylesheet" href="../resources/lesson.css">
- <link rel="stylesheet" href="../resources/lang.css">
- <script type="importmap">
- {
- "imports": {
- "three": "../../build/three.module.js"
- }
- }
- </script>
- </head>
- <body>
- <div class="container">
- <div class="lesson-title">
- <h1>How to dispose of Objects</h1>
- </div>
- <div class="lesson">
- <div class="lesson-main">
-
- <p>
- One important aspect in order to improve performance and avoid memory leaks in your application is the disposal of unused library entities.
- Whenever you create an instance of a *three.js* type, you allocate a certain amount of memory. However, *three.js* creates for specific objects
- like geometries or materials WebGL related entities like buffers or shader programs which are necessary for rendering. It's important to
- highlight that these objects are not released automatically. Instead, the application has to use a special API in order to free such resources.
- This guide provides a brief overview about how this API is used and what objects are relevant in this context.
- </p>
-
- <h2>Geometries</h2>
-
- <p>
- A geometry usually represents vertex information defined as a collection of attributes. *three.js* internally creates an object of type [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLBuffer WebGLBuffer]
- for each attribute. These entities are only deleted if you call `BufferGeometry.dispose()`. If a geometry becomes obsolete in your application,
- execute the method to free all related resources.
- </p>
-
- <h2>Materials</h2>
-
- <p>
- A material defines how objects are rendered. *three.js* uses the information of a material definition in order to construct a shader program for rendering.
- Shader programs can only be deleted if the respective material is disposed. For performance reasons, *three.js* tries to reuse existing
- shader programs if possible. So a shader program is only deleted if all related materials are disposed. You can indicate the disposal of a material by
- executing `Material.dispose()`.
- </p>
-
- <h2>Textures</h2>
-
- <p>
- The disposal of a material has no effect on textures. They are handled separately since a single texture can be used by multiple materials at the same time.
- Whenever you create an instance of `Texture`, three.js internally creates an instance of [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture].
- Similar to buffers, this object can only be deleted by calling `Texture.dispose()`.
- </p>
-
- <p>
- 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 `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.
- </p>
-
- <h2>Render Targets</h2>
-
- <p>
- Objects of type `WebGLRenderTarget` not only allocate an instance of [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture WebGLTexture] but also
- [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLFramebuffer WebGLFramebuffer]s and [link:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderbuffer WebGLRenderbuffer]s
- for realizing custom rendering destinations. These objects are only deallocated by executing `WebGLRenderTarget.dispose()`.
- </p>
-
- <h2>Skinned Mesh</h2>
-
- <p>
- Skinned meshes represent their bone hierarchy as skeletons. If you don't need a skinned mesh anymore, consider to call `Skeleton.dispose()` on the skeleton to free internal resources.
- Keep in mind that skeletons can be shared across multiple skinned meshes, so only call `dispose()` if the skeleton is not used by other active skinned meshes.
- </p>
-
- <h2>Miscellaneous</h2>
-
- <p>
- There are other classes from the examples directory like controls or post processing passes which provide `dispose()` methods in order to remove internal event listeners
- or render targets. In general, it's recommended to check the API or documentation of a class and watch for `dispose()`. If present, you should use it when cleaning things up.
- </p>
-
- <h2>FAQ</h2>
-
- <h3>Why can't *three.js* dispose objects automatically?</h3>
-
- <p>
- This question was asked many times by the community so it's important to clarify this matter. Fact is that *three.js* does not know the lifetime or scope
- of user-created entities like geometries or materials. This is the responsibility of the application. For example even if a material is currently not used for rendering,
- it might be necessary for the next frame. So if the application decides that a certain object can be deleted, it has to notify the engine via calling the respective
- `dispose()` method.
- </p>
-
- <h3>Does removing a mesh from the scene also dispose its geometry and material?</h3>
-
- <p>
- No, you have to explicitly dispose the geometry and material via *dispose()*. Keep in mind that geometries and materials can be shared among 3D objects like meshes.
- </p>
-
- <h3>Does *three.js* provide information about the amount of cached objects?</h3>
-
- <p>
- Yes. It's possible to evaluate `renderer.info`, a special property of the renderer with a series of statistical information about the graphics board memory
- and the rendering process. Among other things, it tells you how many textures, geometries and shader programs are internally stored. If you notice performance problems
- in your application, it's a good idea to debug this property in order to easily identify a memory leak.
- </p>
-
- <h3>What happens when you call `dispose()` on a texture but the image is not loaded yet?</h3>
-
- <p>
- Internal resources for a texture are only allocated if the image has fully loaded. If you dispose a texture before the image was loaded,
- nothing happens. No resources were allocated so there is also no need for clean up.
- </p>
-
- <h3>What happens when I call `dispose()` and then use the respective object at a later point?</h3>
-
- <p>
- That depends. For geometries, materials, textures, render targets and post processing passes the deleted internal resources can be created again by the engine.
- So no runtime error will occur but you might notice a negative performance impact for the current frame, especially when shader programs have to be compiled.
-
- Controls and renderers are an exception. Instances of these classes can not be used after `dispose()` has been called. You have to create new instances in this case.
- </p>
-
- <h3>How should I manage *three.js* objects in my app? When do I know how to dispose things?</h3>
-
- <p>
- In general, there is no definite recommendation for this. It highly depends on the specific use case when calling `dispose()` is appropriate. It's important to highlight that
- it's not always necessary to dispose objects all the time. A good example for this is a game which consists of multiple levels. A good place for object disposal is when
- switching the level. The app could traverse through the old scene and dispose all obsolete materials, geometries and textures. As mentioned in the previous section, it does not
- produce a runtime error if you dispose an object that is actually still in use. The worst thing that can happen is performance drop for a single frame.
- </p>
-
- <h3>Why `renderer.info.memory` is still reporting geometries and textures after traversing the scene and disposing all reachable textures and geometries?</h3>
-
- <p>
- In certain cases, there are some textures and geometries used internally by Three.js
- that are not reachable when traversing the scene graph in order to be disposed.
- It is expected that `renderer.info.memory` will still report them even after a full scene cleanup.
- However, they do not leak, but they are reused on consecutive scene cleanup/repopulating cycles.
-
- These cases could be related to using `material.envMap`, `scene.background`, `scene.environment`,
- or other contexts that would require the engine to create textures or geometries for internal use.
- </p>
-
- <h2>Examples that demonstrate the usage of dispose()</h2>
-
- <p>
- [example:webgl_test_memory WebGL / test / memory]<br />
- [example:webgl_test_memory2 WebGL / test / memory2]<br />
- </p>
- </div>
- </div>
- </div>
- <script src="../resources/prettify.js"></script>
- <script src="../resources/lesson.js"></script>
- </body></html>
|