-
Notifications
You must be signed in to change notification settings - Fork 104
Closed
Description
Originally from #1 (comment) and copy/pasted below.
Currently, managed classes that have some of their methods implemented in C++ (e.g. MonoBehaviours) hold an IntPtr to the C++ implementation class. And they have a Dispose method and a finalizer to make sure that this C++ implementation class is destroyed at the appropriate time. This isn't great for two reasons:
- When nothing else references a managed object, it's possible for the finalizer to be called while the native code is still executing. This problem is described pretty well here: https://www.mono-project.com/docs/advanced/pinvoke/#gc-safe-pinvoke-code. This shouldn't be a problem in our case because we also pass a reference to the managed class to the native code, so effectively the native code keeps the managed object alive. But this is a little precarious.
- Because of the way finalizers impose work on the garbage collector, finalizable classes should be super lightweight and not hold references to other managed objects. But this will not always be the case. Consider MonoBehaviour, for example.
Both of these problems can be solved by holding a SafeHandle-derived class instead of holding an IntPtr directly. The SafeHandle encapsulates the finalization logic, keeping the GC overhead as low as possible. The P/Invoke system is also smart about SafeHandles and will ensure they are not finalized while they are in use in native code.
Metadata
Metadata
Assignees
Labels
No labels