Skip to content
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

WebGLProgram leaking (instances increasing) #28355

Closed
A2H2 opened this issue May 12, 2024 · 5 comments
Closed

WebGLProgram leaking (instances increasing) #28355

A2H2 opened this issue May 12, 2024 · 5 comments
Milestone

Comments

@A2H2
Copy link

A2H2 commented May 12, 2024

Description

WebGLPrograms are not correctly being disposed. I noticed this in my own project, but I can reproduce issue on official https://threejs.org/examples/#webgl_test_memory.
After each cycle of scene recreation (new mesh added / removed / disposed), there is extra +1 new WebGLProgram.

Number of instances seems to be capped at ~131 for my computer which is very strange.
Also then it seems like all above 131 will get deleted correctly which is even more weird.

Only way to correctly get rid of these additional instances is to recreate canvas which I know from my own project. (destroy and create new canvas). As an alternative it is possible to reuse the same instance of material to avoid this extra WebGLPrograms.

WebGLRenderer.info seems to show 1x Program, so either info or memory profiler is wrong.

Reproduction steps

  1. go to https://threejs.org/examples/#webgl_test_memory
  2. (optional) Modify script so it only updates slower (for example once per sec)
    I changed animate script to following:
    function animate() {
    setTimeout( animate, 1000 );
    render();
    }
  3. Open Chrome Memory tab in developers console. Select first option - Heap snapshot
  4. Do several snapshots as time progress and filter WebGLProgram
  5. Notice that intances are increasing up to (also in compare mode you see those instances are not deleted)

Code

One present at https://threejs.org/examples/#webgl_test_memory

Live example

https://threejs.org/examples/#webgl_test_memory

Screenshots

Live (unmodified) webgl_test_memory screenshot 1
image

Live (unmodified) webgl_test_memory screenshot 2
image

Modified webgl_test_memory 1
image

Modified webgl_test_memory 2
image

Version

i can reproduce on 159 and 164

Device

Desktop

Browser

Chrome version 124.0.6367.158 (Official Build) (64-bit)

OS

Windows

@A2H2 A2H2 changed the title WebGLProgram leaking (instance increasing) WebGLProgram leaking (instances increasing) May 12, 2024
@Mugen87
Copy link
Collaborator

Mugen87 commented May 14, 2024

I have debugged the example and it seems the internal program cache does not retain outdated program references. When you call material.dispose(), the renderer checks if an instance of WebGLProgram is still required and if not, releases it and removes internal references. The code that triggers these operations is:

function releaseMaterialProgramReferences( material ) {
const programs = properties.get( material ).programs;
if ( programs !== undefined ) {
programs.forEach( function ( program ) {
programCache.releaseProgram( program );
} );
if ( material.isShaderMaterial ) {
programCache.releaseShaderCache( material );
}
}
}

When a program is removed, keep in mind that it is not immediately removed from memory. That happens when the GC runs and we can't influence when the JS environment decides to run it.

@A2H2
Copy link
Author

A2H2 commented May 14, 2024

Hello @Mugen87, thank you for looking into this issue. I forced garbage collection (in memory profile tab its 5th icon, first is to take heap memory snapshot), but unfortunatelly it didnt garbage collectied it in next snapshot.

What seems to be leaking is WebGLProgram from webgl context, a gpu resource, not the class wrapper which is called WebGLProgram too. To confirm this I renamed wrapper class to be sure.

It looks like this WebGLProgram program instance reference is still somewhere and it is preventing garbage collection. I already spend few hours on this and I am more familiar with the issue, but I am not able to figure out this out yet.

I also found some "similar" issue from that past. I am not sure if its related or not yet.
#19645

@Mugen87
Copy link
Collaborator

Mugen87 commented May 15, 2024

I also found some "similar" issue from that past. I am not sure if its related or not yet.
#19645

It is not related, imo. Render states have no references to programs.

@Mugen87
Copy link
Collaborator

Mugen87 commented May 16, 2024

I've checked the relevant code base again I don't think the root cause is on our side. Especially the behavior you have described here makes me think this is a browser related issue:

Number of instances seems to be capped at ~131 for my computer which is very strange.
Also then it seems like all above 131 will get deleted correctly which is even more weird.

To me, this does not look like a memory leak. I suspect what we see is some sort of cashing mechanism of the browser to retain programs for a potential later use. Even if an app does not use a program for rendering anymore, it might be use it at a later point. Next to optimizations on engine levels, WebGL implementations apply optimizations as well to avoid unnecessary overhead. If the browser caching is implemented correctly, is a different question.

But to be honest, if there is no ongoing growing memory allocation that eventually slows down the app or crashes the tab, I would not worry about 131 instances of WebGLProgram retained somewhere in memory. If you insist to report it, do it here: https://issues.chromium.org/issues.

@Mugen87 Mugen87 closed this as not planned Won't fix, can't repro, duplicate, stale May 16, 2024
@A2H2
Copy link
Author

A2H2 commented May 16, 2024

I kind of agree with your conclusion. If I find some other reason or evidence I will report it.
I tried several code changes to get rid of those WebGLPrograms but I was unable to achieve it.

Also thanks for the link to chromium I will try to ask for advice / confirmation there.

@Mugen87 Mugen87 added this to the r165 milestone May 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants