I recently started with C++ plug-in development using the debug Rhino exectuable and noticed that when I have a certain .NET plug-in loaded that I get memory leaks reported. The amount of bytes is 2208 (many times) and when using LookForLeaks with that number, I get:
ON_UuidList::Array
ON_UuidList::Array
ON_UuidList::Array
ON_UuidList::Array
ON_UuidList::Array
ON_Xform_Scale
unavailable - (Load plug-ins before running LookForLeaks)
unavailable - (Load plug-ins before running LookForLeaks)
unavailable - (Load plug-ins before running LookForLeaks)
unavailable - (Load plug-ins before running LookForLeaks)
unavailable - (Load plug-ins before running LookForLeaks)
Even if I load the plug-in before I issue LookForLeaks, I do not get more information for the callstack.
Is there more that I can do to get to the bottom of this?
Another one (same stack trace for 192, 168, 120 and 96 byte leak). I am opening a panel and draw some curves in a DisplayConduit when this happens. I am very puzzled by the CRhinoView::OnWindowMeshRepairWizard in the stack trace - I don’t open the mesh repair wizard at all!
Visual Studio is not capable of tracking some of Rhino’s memory, due to the memory manager we use. That said, it is possible that we’re leaking, or your plug-in is leaking. Can you provide the code to a sample command that you think is leaking when it shouldn’t?
Well, I was kinda hoping that using C# would free me from memory leaks, esp. of this magnitude. I will try and get an example in which this behavior is manifested.
To be continued…
Yes, this seems to be the solution. I have significantly reduced the amount of memory leaked by actively reclaiming resources with Dispose(), and GC.Collect() after the command ends.
When doing the command that previously leaked 3.5 MB per time it was used, now this is down to a few kB.
It is not so much a true memory leak as it is a combination of
late garbage collection and
no garbage collection prior to Rhino exit
The second point leads to leak messages when using the debug version of Rhino. To me this makes sense as each geometry object being created (not structs) will allocate memory that is freed when the .NET finalizer is run, this is clear from the RhinoCommon code. If that finalizer is not run prior to exiting Rhino, the unfreed memory is reported as leaks.
I leak when Rhino shuts down on purpose. The classes that can hold userdata are not deleted when Rhino closes. This is because the userdata chains can include classes with information located in DLLs that have already been unloaded when the final .NET finalizer kicks in. We used to have some very difficult to track crashes on shutdown way back before I added the code to just leak and let the operating system reclaim the memory when the process dies.
Thanks @stevebaer for your insight, I can imagine that such crashes are very hard to pin down and that letting the OS reclaim memory is a much more robust solution.