-
-
Notifications
You must be signed in to change notification settings - Fork 36k
WebGPU: Fix Renderer
not being garbage collected
#31798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
This reverts commit a70d486.
📦 Bundle sizeFull ESM build, minified and gzipped.
🌳 Bundle size after tree-shakingMinimal build including a renderer, camera, empty scene, and dependencies.
|
|
||
if ( this._removeListeners[ geometry.id ] !== undefined ) { | ||
|
||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure whether we can early-exit for already initialized geometries.
* @private | ||
* @type {Object} | ||
*/ | ||
this._removeListeners = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If Geometry.id
cannot be a reliable source of uniqueness, I will replace it with a Map.
As an alternative, how about we do not register an dispose event listener for The changes in If that is not acceptable, I would indeed suggest to stop using |
After thinking a bit, I think neither adding an exception for I've seen many third-party libraries that rely on geometries in the global scope, which reasonably assume that memory is held only for geometry that is not disposed, not for the entire renderer-related memory. Additionally, If you can elaborate on what's hard to follow, I'm happy to adjust and add comments. |
I've tried to reproduce the approach from |
@Mugen87 Thank you. I tested your code but it doesn't solve this. Your |
With ECMAScript 2021, we could use Maybe we could also do this |
Technically, yes, but I haven't traced all the references that What confuses me is that you are trying to fix this issue (or to minimize the leaked memory footprint) without removing event listeners that |
Sorry for not explaining my hesitation but the need for separate functions for removing the listeners feels like a bandage as well. I'm just not feeling well with it and not with applying it to potentially other modules. I know this is somewhat a subjective decision but I feel we need to look for other solutions. |
Do you mind elaborate why? Is that also true for similar structures like |
I would also like some elaboration on this, if only to possibly understand how WeakRef and WeakMap might be related and why WeakMap does not seem to work as intended when caching GPU resources. MDN seems to strongly discourage WeakRef use https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakRef#avoid_where_possible. |
The gist of my opinion is that Another reason is that In my experience, there is almost always a way that doesn't require weak references (not just in JS, if uses an advanced GC). In this case, remove event listeners. As to your hesitation about having functions to remove listeners (which I think is a very common way to implement cleanup functions, though), the following code does basically the same: // In constructor
this._geometryListeners = {}
// In initGeometry()
this._geometryListeners[geometry.id] = { geometry, onDispose }
// In dispose()
for (const key in this._geometryListeners) {
const { geometry, onDispose } = this._geometryListeners[key]
geometry.removeEventListener('dispose', onDispose)
} |
Description
This PR potentially fixes an issue that
Renderer
and all associated memory are not garbage collected (I say "potentially" because there may be other leak sources).The geometry used in
QuadMesh
is instantiated in a global variable, andGeometries
adds a dispose event listener that capturesthis
in a closure and is never removed because the geometry is never disposed.Geometries
holds a reference toAttributes
, which holds a reference to aBackend
, which holds a reference toRenderer
, thus the GC cannot collect the entire renderer-related CPU memory.I initially attempted to move
QuadGeometry
insideQuadMesh
, but manyQuadMesh
instances are also instantiated in global variables. If we keep using it that way, we need to address it inGeometries
.