we are working with 3D point clouds (as 3DTiles) and Cesium for quite some time now but recently we got our hands on a really big and dense cloud.
As expected this needs much more memory and eventually gets the browsers to crash.
I already read through most of what I could find regarding this topic (different options for the tileset, the viewer, etc.) but I am stuck at a rather simple question:
What is the expected behaviour for used memory of the browser (or more accurate the tab in which Cesium is running) when tiles/points get unload?
For me it looks like the memory is never freed after the tiles got unloaded.
Steps to replicate:
Load a big point cloud with maximumMemoryUsage: 0.
Rotate, zoom, translate to load many tiles. Eventually get around 2 GB (or any other high umber) of used memory.
Move away from the point cloud, zoom out very far or add some clipping planes to make tiles unload.
Multiple tileUnload events are received and the 3D Tiles Inspector shows that only a fraction of the points/tiles are still loaded (or maybe even down to zero points/tiles loaded).
The problem is that used memory (in Windows and Chromes task managers) stays at around the level it was when the tileset was fully loaded (e.g. 2 GB). GPU memory usage is dropping as expected.
I tried to create a sandcastle with this problem by "abusing" the 3D Tiles Point Cloud example and adding the tileset multiple times with slightly different translation (quite an artistic effect :p).
For me it shows the same behaviour (when I am zooming in at the tower of the churches I manage to get around 1 or 2 million points and 1 to 2 GB of memory usage).
If you try it out take a look at the used memory, when it is high zoom out until the whole tileset is unloaded and check used memory again.
Oh, looks like I copied the wrong sand castle link. The one in the original post should work two, but with the following slight modification it's easier to get more points in the view:
Thanks for reporting this. I think my best guess is that either Chrome is holding on to this memory, which you can confirm by forcing a garbage collection in the dev tools to see if it clears up the memory - or that when a tileset is unloaded, there’s a memory leak somewhere in CesiumJS that’s holding a reference to some objects so it never gets cleaned.
I’m going to investigate this more when I get a chance, but in the mean time, one more tip is to try taking a heap snapshot using Chrome’s devtools, which will tell us exactly what’s clogging up all that memory.
Actually I already tried investigating a bit with heap snapshots and garbage collection. A forced Garbage Collection doesn't seem to free the memory so it looks like it's still hold on by something.
I tried getting my mind around some heap snapshots but I didn't find a good point to start looking for the problem as I am not very familiar with the structure of these snapshots.
I just loaded the Sandcastle from my previous post again and couldn't really reproduce the effect now (much memory is freed and only around 200 or 300 MB over the pre-loading-the-tileset value are kept). Maybe it's a memory leak in our project and not a problem of Cesium at all. Nevertheless I would appreciate if someone would try it out with the sandcastle and report back to me for clarification
Assumed that it's not Cesium but our code, dose someone has tips on what could possibly cause this? We reference the tileset itself in the code but this shouldn't keep the tiles from unloading, shouldn't it?
Could there be any case were the tiles are forced to stay in memory without directly referencing them?
We use VueJs and my best guess is, that it might betrying to make the tileset with all its tiles reactive. I will investigate on this but any other general idea is highly appreciated
If I can find the problem I will report back. Hopefully it's just our fault
Well.. I just spent another 15 minutes on this and found the problem. Really was our code (and it really was VueJs).
Just another case of "easy to fix as soon as you have the right idea"
Awesome, thanks for confirming Marcel! Do you have any tips to share for VueJS users here in case anyone runs into this in the future? Was it something VueJS was doing by default that you had to work around?
Sure!
It's more of a general problem you can encounter with VueJs.
The tileset was part of an Object that I had referenced in the data function/Object of the Vue instance. This made Vue starting to make everything in the tileset reactive (by putting its getters and setter on it etc.)
Looks like this even went as deep as the single 3DTiles are inside the tileset. So for every loaded 3DTile Vue had to add reactivity and it hold its references to the 3DTiles even after Cesium "unloaded" them.
Not sure about the exact technical background but I think this is more or less what happened.
So the solution was to not put the tileset or anything that is referencing it into the data function of the Vue instance. As I said this is a general VueJS thing and not exactly Cesium-related. This problem should be considered for everything one puts into the data function. I am glad that I could give a good example for the why
I appreciate the explanation! I actually ran into something similar with one of the React+Cesium plugins, where it says:
If “Cesium read only props” are changed in React component, the Cesium element will be destroyed and reinitialized. It can be a cause of performance deterioration. Please use carefully to avoid changing as much as possible.
So I can see how having a VueJS+Cesium plugin could be helpful to account for these kinds of caveats.