Object lifetimes
VTK counts references and frees an object when the last one goes. A C# proxy holds one; Dispose drops it at once, the finalizer once the garbage collector finds the proxy unreachable.
var points = new vtkPoints(); // New(): 1 reference, the proxy's
using var polyData = new vtkPolyData();
polyData.SetPoints(points); // 2: the poly data's too
var again = polyData.GetPoints(); // 3: a returned object, another proxy, another reference
// Dispose drops the proxy's reference at once; the object goes when no one holds it
again.Dispose(); // 2
points.Dispose(); // 1: the poly data's
GetReferenceCount() counts VTK's own references too: a new vtkSphereSource reports 2.
using (var reader = new vtkXMLUnstructuredGridReader())
{
// ... read, take what's needed
}
// or for the rest of the block
using var grid = new vtkUnstructuredGrid();
What VTK keeps
What VTK holds stays alive, whatever happens to its proxies:
// VTK counts its own references: the actor holds the mapper after its proxy is gone
using var actor = new vtkActor();
using (var mapper = new vtkPolyDataMapper())
{
actor.SetMapper(mapper);
}
using var held = actor.GetMapper(); // a new proxy for the same mapper
The same goes for a filter's input and output, a renderer's actors, and an observer VTK holds, a C# vtkCommand included (Observers and messages). A proxy isn't the object: GetMapper() twice gives two proxies, each with a reference; NativePointer tells whether they're the same object.
When to dispose
The garbage collector sees only the small proxy, not the native memory behind it.
| Dispose promptly | Why |
|---|---|
| render windows, renderers, mappers, actors, textures | they release OpenGL resources, which needs the thread that renders |
| large data sets and arrays | the memory goes only with the last reference |
| readers and filters | each holds its output |
| small objects | no need: the finalizer is fine |
Threads
The finalizer releases on its own thread, where no OpenGL context is current: fine for data, not for rendering objects. Dispose those on the thread that renders, or set VtkFinalizer.Context to its SynchronizationContext: the finalizer then posts the releases there (Rendering and hosting). Dispose releases on the calling thread. A release posted to a context whose thread has ended doesn't happen.