My observation in practice has been that GC.SuppressFinalize does not always suppress the call to the finalizer. It could be that the finalizer gets called nontheless. I won
When an object with a user-defined finalizer is constructed, the runtime has to keep an internal reference to it so when it becomes unreachable in user code it can be still have the finalizer called in the runtime's finalization thread. Considering that time is of the essence when calling finalizers, it makes no sense to keep the objects in the queue if the user has requested them be suppressed. In my test CLI implementation, I keep a SuppressFinalizer flag in the header of objects that have user-defined finalizers. If the flag is true when the finalizer thread reaches that object in the queue, the finalizer call is skipped. I don't remove the object from the queue so I can keep the call to GC.SuppressFinalize()
O(1) instead of O(N), where N is the number of allocated finalizable objects (I might change this policy to a deferred removal policy later).