What is the proper way to trigger an UpdateGeometry on terrain? Every code path seems locked down as strictly private. I have deformable terrain working… but to trigger UpdateGeometry I have to kludge set data to nil and then set it again to the terrain data. This works… but also seems to cause running out of memory really quickly. I am tempted to just expose the functionality which is so important… but figure there must be a correct way that doesn’t involve changing library code.
Hmm. Calling updategeometry about 50 times runs out of heap. Do I need to do something to insure the garbage is taken out?
I figured out how to get the change to trigger UpdateGeometry by calling DoChange from within the terrain data class. However I can still only do about 50 changes before it runs out of memory. It is as if it isn’t disposing the old triangle sets.
I did some testing, and it doesn’t seem like UpdateGeometry
leaks memory. After calling it more than 300 times, the application memory usage remains similar.
My test:
- I added
// Changing Smoothness (see TCastleTerrainNoise.SetSmoothness implementation)
// calls TCastleTerrain.UpdateGeometry each time.
TerrainNoise1.Smoothness := TerrainNoise1.Smoothness + SecondsPassed * 0.1;
Inc(ChangeCount);
WritelnLog('Smoothness change: %f (change num %d)', [
TerrainNoise1.Smoothness,
ChangeCount
]);
to the TViewMain.Update
implementation in examples/terrain/code/gameviewmain.pas
in CGE. So in each update, I change TerrainNoise1.Smoothness which causes UpdateGeometry
(I see the terrain actually getting smoother, so I know it works).
Here’s the screenshot after a while:
So, I cannot reproduce the problem on my own. Can you post a testcase to reproduce the issue? Maybe there’s something specific in how you use it to cause the memory leak?
I am back to working on my projects after a couple months off. I have updated to the latest cge. I still have this problem. I can modify the terrain with a mouseclick. I have a grid of singles 100x100 for each tile (I have multiple tiles). A click adds or removes a little at the clicked point. This then calls DoChange on the TCastleTerrainData that wraps my grid of singles. This triggers the UpdateGeometry from the tile. If I click as fast as I can, it runs out of heap after 113 clicks. But if I click really slowly, I can can go way beyond 113, maybe indefinitely. So it seems to me like the garbage collection is falling behind? It is not easy to give you a simple testcase. I could give you access to the whole repository. It is based off of wyrd-forest.
I have a body and collider on the terrain. If I don’t add these, it doesn’t eat memory when I rebuild the terrain after deforming.
(*
Body := TCastleRigidBody.Create(Self);
TerrainTile.AddBehavior(Body);
Collider := TCastleMeshCollider.Create(Self);
Collider.Mesh := TerrainTile;
Collider.Restitution := 0.3;
TerrainTile.AddBehavior(Collider);*)
Thank you! Thanks to this info, I was able to reproduce and fix the problem
At each mesh change, TCastleMeshCollider was internally leaking memory.
The fix is committed and pushed ( Fix memory leak due to leaving TKraftMesh instances · castle-engine/castle-engine@12d0f04 · GitHub ). As usual. give Jenkins a few hours to rebuild the engine, and the version with the fix will be available on Download | Castle Game Engine . You can observe the page Comparing snapshot...master · castle-engine/castle-engine · GitHub to know when exactly it will be available: if that page will no longer show the commit “Fix memory leak due to leaving TKraftMesh instances” → then the fix is included in the build.
Note that you speculated in older posts about garbage collector and freeing with delay being an issue: To be clear, there is no such thing in our X3D nodes. We do reference-counting for X3D nodes, but when the count drops to zero → the node is freed immediately, without any delay. (At least for now – I don’t preclude more complicated schemes for freeing / reuse in the future.)
Thankyou Thankyou Thankyou! This was a roadblock.