Free Memory of Previous Outputs of Grasshopper Component

Hello everyone

I’m working in a grasshopper plugin that uses native C++ code, which is wrapped and can be called from C# as shown in this example. The results are passed to C# as IntPtr and are themselves contained in C# classes to make them a little easier to handle. These C# classes are finally passed as outputs from one component to another.
My problem is the following: I need to free the memory that was allocated by the native code, however I cannot do so within the component as they are part of the output that is passed to other components. I tried to put the code for freeing said memory inside the destructor of the C# classes, however it appears these are never called and so the memory is never freed.

What would be the proper way to pass custom classes between grasshopper components in order allow for freeing the memory once they are no longer needed?
Or do I have the wrong approach altogether and should be doing something else?

~robin

Hi @robin_l,

In general, you shouldn’t need to worry about memory management in .NET, as objects will be garbage collected as needed.

That said, if you are creating .NET classes that hold onto unmanaged pointers, then you will want to make sure the memory allocated for the C++ objects is recovered when the .NET objects are disposed. You do this by inheriting your .NET classes from IDisposable, as it provides a mechanism for releasing unmanaged resources.

For example, let’s say your C++ library has a CMyClass class object and in .NET you want to represent this as MyClass. You could define MyClass like this:

public class MyClass : IDisposable
{
  IntPtr m_ptr; // CMyClass*

  public MyClass()
  {
    m_ptr = UnsafeNativeMethods.CMyClass_New();
  }

  #region IDisposable implementation

  /// <summary>
  /// Passively reclaims unmanaged resources when the class user did not explicitly call Dispose().
  /// </summary>
  ~MyClass()
  {
    // Passively reclaims unmanaged resources when the
    // class user did not explicitly call Dispose().
    Dispose(false);
  }

  /// <summary>
  /// Actively reclaims unmanaged resources that this instance uses.
  /// </summary>
  public void Dispose()
  {
    // Actively reclaims unmanaged resources that this instance uses.
    Dispose(true);
    GC.SuppressFinalize(this);
  }

  /// <summary>
  /// This method is called with argument true when class user calls Dispose(), 
  /// while with argument false when the Garbage Collector invokes the finalizer,
  /// or Finalize() method. You must reclaim all used unmanaged resources in both cases,
  /// and can use this chance to call Dispose on disposable fields if the argument is true.
  /// Also, you must call the base virtual method within your overriding method.
  /// </summary>
  protected virtual void Dispose(bool disposing)
  {
    if (m_ptr != IntPtr.Zero)
      UnsafeNativeMethods.CMyClass(m_ptr);
    m_ptr = IntPtr.Zero;
  }

  #endregion
}

The two unsafe native methods would look like this:

SDK_C_FUNCTION CMyClass* CMyClass_New()
{
  return new CMyClass();
}

SDK_C_FUNCTION void CMyClass_Delete(CMyClass* ptr)
{
  if (nullptr != ptr)
    delete ptr;
}

Does this help?

– Dale

In addition to this, you may want to also call GC.AddMemoryPressure and GC.RemoveMemoryPressure during construction and deletion

https://docs.microsoft.com/en-us/dotnet/api/system.gc.addmemorypressure?view=netframework-4.8

1 Like

Thank you @dale and @stevebaer . I will investigate this when I get back to the office on Monday. As you can probably tell I am primarily a C++ developer, so the reading material on C# is greatly appreciated.

~robin