I am developing a plugin for Rhino 8 using C++ SDK and I have strange and undesirable behavior with regard to memory management (garbage collection). Maybe someone can give me an idea of what’s going on? Here’s what I got:
I need to create a single very large mesh from a huge number of small “sub-meshes” created dynamically with new ON_Mesh(...)
. I manage these “sub-meshes” with ON_MeshRef and pass shared_ptr to append the final mesh (in a fast way):
std::vector<std::shared_ptr<const ON_Mesh>> meshpiece;
...
// create a mesh with few faces and manage it by meshRef (the mesh is created elsewhere)
...
for (i = start; i < end; i++) {
std::shared_ptr<ON_Mesh> sharedptr = meshRef.SharedMesh();
meshRef.Clear();
meshpiece.push_back(std::move(sharedptr));
}
...
ON_Mesh finalMesh;
finalMesh.Append(meshpiece);
...
// clear/destroy 'meshpiece'
...
// eventually destroy finalMesh
I have separate mesh pieces created first (in multiple threads) which go into the final mesh (though the issue is not thread dependent, it happens with 1 thread as well).
Here’s what I observe with memory consumption for a smaller example when I repeatedly run my plugin (and I don’t do anything else in Rhino):
Thin spikes correspond to each run of my code which allocates and deallocates ~3.7Gb of memory (for this case). The first 3 spikes look good, but starting from the 4th spike not all memory is released. However, after every 3 cycles the memory is released going down to ~1.2Gb (e.g., as pointed by the red arrow). This 3-spikes cycle seems to be consistent, after which (I guess) garbage collector kicks-in. However, memory footprint grows within 3-spike frame (going from ~2.4Gb to 3.3Gb). And at the end of all this, memory is not released at all (garbage collector kicks-in much-much later).
I don’t understand that even if I release all my memory, why Rhino as a process starts consuming more memory for these 3-spike intervals? It appears that I need to run my code 3 (or more) times for Rhino to release memory. Note that I don’t do any additional operations, only run my code periodically. With this, if I don’t get to the point when garbage collector kicks-in, Rhino stays with high memory footprint (like at the end).
Is there a way to force garbage collector to run after my code every time? Note that I am using native C++ SDK.
This is a small case, when I run more realistic large case, memory consumption easily goes into 50-100Gb and it makes Rhino unusable.
Thanks for any advice!