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

Memory leak caused by non disposed scene, when using routes #449

Closed
5 tasks done
fakedob opened this issue Nov 19, 2023 · 14 comments · Fixed by #463 or #490
Closed
5 tasks done

Memory leak caused by non disposed scene, when using routes #449

fakedob opened this issue Nov 19, 2023 · 14 comments · Fixed by #463 or #490
Assignees
Labels
bug Something isn't working p4-important-bug Violate documented behavior or significantly improve performance (priority) performance

Comments

@fakedob
Copy link

fakedob commented Nov 19, 2023

Describe the bug

In our project, we use a bit big bigger models and we test our app on mobile browsers. While observing the memory, it became clear that unmounting the TresCanvas, does not properly dispose the scene and some (maybe all) internal objects. So navigating in and out a few times on iOS device, cause the page to crash and reload, because it runs out of memory.

Screenshot 2023-11-19 at 20 15 16

Unfortunately, my understanding of three.js is not much, but I had similar issues in the past and it was related to the way the scene and objects, that were added to the scene, being not properly disposed. Its possible that some references to some internal TresJS objects are also the cause of the issue. I just dont know.

Its also possible that I am missing something in the way I use the framework (which will be the best for me), so hopefully someone can give me a hand with this.

Thank you!

Reproduction

https://stackblitz.com/edit/tresjs-basic-tmk778

Steps to reproduce

To reproduce, open the reproduction link in a Chromium browser and use the Memory tab in the dev tools.
At the top of the web page, you will find a basic navigation, that routes into two separate pages, where "The Experience" loads the TresCanvas and "Home" is used to unmount the other one.

System Info

No response

Used Package Manager

npm

Code of Conduct

@alvarosabu alvarosabu self-assigned this Nov 23, 2023
@alvarosabu alvarosabu added bug Something isn't working performance labels Nov 23, 2023
@alvarosabu
Copy link
Member

Thanks for raising this @fakedob I will take a look to it 🙏🏻

@alvarosabu
Copy link
Member

@fakedob can you confirm for me this is only happening with 3D models? If you use geometries with textures you get the same result? Just to narrow down I'm doing some tests currently

@fakedob
Copy link
Author

fakedob commented Dec 6, 2023

Hey @alvarosabu sorry for delay, I wanted to be sure I test it properly before replying. I have loaded the test with the house and graves into a page for this test and went in and out using the router. The result is the same, basically, it loads the assets and does not dispose them upon leave, leading into 1.5mb left into memory.

I have checked the commit in the pull request and understood, that you are trying to dispose some of the objects while traversing the main one. Have you looked into this thread and proposed solution?

@alvarosabu
Copy link
Member

Hey @fakedob I just tried the solution they provided but I am having trouble measuring the before and after, looking at the total allocated size remains similar but then looking for specific classes inside they are removed when dispose of.

How do you check if the geometries, materials, and textures have been properly disposed of and free out of memory?

@alvarosabu
Copy link
Member

alvarosabu commented Dec 9, 2023

Investigating a little I saw this explanation @fakedob https://discourse.threejs.org/t/memory-usage-increases-upon-loading-model/58846/4

Disposal does not have anything to do with the memory you’re looking at. Dispose disposes assets from the GPU. The memory snapshots you’re sharing are CPU memory / JS heap stack.

Make sure you’re not storing your meshes in any arrays, besides scene.children (I mean, you can and often need to, but you have to remember to remove the meshes from said arrays - otherwise they remain in memory forever.) Meshes stored in arrays that are used during the runtime will not be removed from memory until the mesh is removed from said array.
Make sure you’re not assigning meshes as properties of other meshes / objects - ex. object.characterMeshRef = myMesh - this mesh will not disappear from the memory until you unassign it from that property - ex. object.characterMeshRef = null.
Do not console log stuff when measuring the memory. References expanded in the console remain in-memory.

@alvarosabu
Copy link
Member

Hi @yyx990803 thanks for offering your help. Just added you here for proper context

When using v-if on a component belonging to the Tres custom renderer, the remove method of the nodeOps.ts is called and the properties like geometry and material are disposed from GPU and removed from memory (CPU) https://github.com/Tresjs/tres/blob/bugfix/449-memory-management/src/core/nodeOps.ts#L184-L195

Memory.diposal.v-if.mp4

When navigating to a new route, remove method is not called (I guess that's expected) but the onUnmounted method of the <TresCanvas /> (the component responsible for rendering the tres custom renderer) is being called, however, for some reason by manual disposing of the scene (similar to what happens inside the remove method) doesn't seem to free the references of the properties on the memory.

Memory.disposal.vue-router.mp4

My rough guess is that they continue being referenced on the custom renderer and that's why the garbage collector cannot free them but I'm not sure of this. No idea how to "dispose" the custom render.

Here is a reproduction link https://stackblitz.com/edit/tresjs-basic-ejbcex?file=package.json,src%2Fmain.ts,src%2Fpages%2Findex.vue,src%2Fpages%2Fempty.vue,src%2Fstyle.css

To debug maybe is gonna be easier to clone https://github.com/Tresjs/tres/tree/bugfix/449-memory-management and run the playground npm run dev and go to /perf/ route.

Thanks again 🙏🏻

@alvarosabu
Copy link
Member

Hey @fakedob so we still investigating, we did some improvements but the issue of memory allocation not being released on route change is still there and it doesn't seem trivial. I will get back to you as soon we have news. Sorry

@Sea-DH1
Copy link

Sea-DH1 commented Feb 6, 2024

Hey @fakedob so we still investigating, we did some improvements but the issue of memory allocation not being released on route change is still there and it doesn't seem trivial. I will get back to you as soon we have news. Sorry

I think this method can be used to create a calling method inside the primitive and call it directly when the scene is destroyed.
https://threejs.org/manual/#en/cleanup

@fakedob
Copy link
Author

fakedob commented Feb 6, 2024

Thank you so much for your help guys, I will try this method and hope it will do the trick. Temporarily, as a workaround, I am loading a separate page into an iframe and control it via post messages. It is very limiting approach, but at least it doesnt crash the web app on mobile.

I will let you know how does it behave when calling the cleanup method asap.

@alvarosabu alvarosabu mentioned this issue Mar 20, 2024
Closed
13 tasks
@alvarosabu alvarosabu moved this to Todo in Team Board Mar 31, 2024
@alvarosabu alvarosabu added the p4-important-bug Violate documented behavior or significantly improve performance (priority) label Mar 31, 2024
@alvarosabu alvarosabu moved this from Todo to In Progress in Team Board Apr 1, 2024
@alvarosabu alvarosabu linked a pull request Apr 24, 2024 that will close this issue
8 tasks
@github-project-automation github-project-automation bot moved this from In Progress to Done in Team Board May 30, 2024
@JLK-666
Copy link

JLK-666 commented Dec 6, 2024

Hello, I also encountered this problem. Is it solved now
I used your new dispose() function but it didn't solve the problem

@fakedob
Copy link
Author

fakedob commented Dec 6, 2024

No, unfortunately, I didn't find an easy way around. The way I approached this problem finally, was to load the thres renderer into an iframe, which basically runs another window process, thus, when navigating away, the browser takes care of its memory. I know it looks a bit dirty, but it works. Just to give you another hint, I made a 2 way communication between the main and the child process to pass data of what needs to be loaded etc and control it as I would do with APIs. I hope this information help you, good luck.

@JLK-666
Copy link

JLK-666 commented Dec 9, 2024

@alvarosabu Hello, I also encountered this problem. Is it solved now

@alvarosabu
Copy link
Member

@alvarosabu Hello, I also encountered this problem. Is it solved now

Is it a question?

@JLK-666
Copy link

JLK-666 commented Dec 12, 2024

@alvarosabu Hello, I also encountered this problem. Is it solved now

Is it a question?
@alvarosabu
yes,I used your new dispose() function but it didn't solve the problem

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working p4-important-bug Violate documented behavior or significantly improve performance (priority) performance
Projects
Status: Done
4 participants