we have a Rhino 6 plugin and one of our users reported a Rhino crash when they move objects around (with gumball or otherwise). I was not able to reproduce this with Rhino 7.
I’ve tracked it down to a crash in the GC finalizer thread when we try to access mesh properties such as Vertices, Normals or Faces. The user also reported that this issue seems to get worse the bigger the project is. As the issue comes from the finalizer it’s not 100% reproducible but can definitely be triggered after moving objects around for a minute or two.
In general, what we do in our plugin is that we are subscribed to events such as RhinoDoc.AddRhinoObject. We collect all the added/changed/deleted objects and then process those changes in the next RhinoApp.Idle.
Part of that processing is reading the mesh from newly added objects and this is where the crash occurs.
The objects that we are accessing at this point are all valid (via the IsValid check) and not disposed.
Here is a mini crashdump, attach with Mixed. The exception is in the GC Finalizer Thread and our plugin is trying to access the MeshFaceList in the Main Thread. Rhino crash after moving objects.zip (674.7 KB)
Can we avoid this crash in any way? Is this there a known issue for this case?
It looks like I found the issue on our side. We did use RhinoObject.GetRenderMeshes to Precalculate the meshes but did not keep the returned references so they ended up being garbage collected. When we then later used rhinoObject.GetMeshes()…Face it ran into this crash.
Use the code below
Create a project in Rhino6 with a good number of 3d objects ~1000
Move the objects until crash with a short delay between moves to trigger the idle event
The fix is to not discard the references returned by GetRenderMeshes
using System;
using System.Collections.Generic;
using Rhino;
using Rhino.DocObjects;
using Rhino.Geometry;
public class RhinoAddedObserver
{
private List<RhinoObject> _addedObjects;
public RhinoAddedObserver()
{
RhinoDoc.AddRhinoObject += OnAddRhinoObject;
}
private void OnAddRhinoObject(object sender, RhinoObjectEventArgs rhinoObjectEventArgs)
{
if (_addedObjects == null)
{
_addedObjects = new List<RhinoObject>();
RhinoApp.Idle += RhinoAppOnIdle;
}
_addedObjects.Add(rhinoObjectEventArgs.TheObject);
}
private void PrecalculateMeshes()
{
RhinoObject.GetRenderMeshes(_addedObjects, true, false);
}
private void RhinoAppOnIdle(object o, EventArgs eventArgs)
{
RhinoApp.Idle -= RhinoAppOnIdle;
PrecalculateMeshes();
foreach (var addedObject in _addedObjects)
{
foreach (var mesh in addedObject.GetMeshes(MeshType.Render))
{
if (mesh != null && mesh.IsValid)
{
var vertices = mesh.Vertices;
var normals = mesh.Normals;
var meshFaceList = mesh.Faces;
}
}
}
_addedObjects = null;
}
}
Rhino still crashes with your sample code. The problem is that the ObjRef[] that is returned from RhinoObject.GetRenderMeshes is unused in that separate method.
At some random point during the loop of reading the meshes from the objects in OnIdle the finalizer cleans up those ObjRef and causes a crash.
That is exactly the cause of the crash. If I don’t use the return values, Rhino crashes. If I assign them to a local variable in the scope of the parsing logic it does not crash.