Skip to content

Preview Ruby 4.1 is a preview. It can change before the final release. Switch to Ruby 4.0 →

class method

ObjectSpace.define_finalizer

(untyped obj, ^(::Integer id) -> void aProc) -> [ ::Integer, ::Proc ]
(untyped obj) { (::Integer id) -> void } -> [ ::Integer, ::Proc ]
ObjectSpace.define_finalizer(obj) {|id| ... } → array
ObjectSpace.define_finalizer(obj, finalizer) → array

Adds a new finalizer for obj that is called when obj is destroyed by the garbage collector or when Ruby shuts down (which ever comes first).

With a block given, uses the block as the callback. Without a block given, uses a callable object finalizer as the callback. The callback is called when obj is destroyed with a single argument id which is the object ID of obj (see Object#object_id).

The return value is an array [0, callback], where callback is a Proc created from the block if one was given or finalizer otherwise.

Note that defining a finalizer in an instance method of the object may prevent the object from being garbage collected since if the block or finalizer refers to obj then obj will never be reclaimed by the garbage collector. For example, the following script demonstrates the issue:

Example
class Foo
  def define_final
    ObjectSpace.define_finalizer(self) do |id|
      puts "Running finalizer for #{id}!"
    end
  end
end

obj = Foo.new
obj.define_final

There are two patterns to solve this issue:

  • Create the finalizer in a non-instance method so it can safely capture the needed state:

    Example
    class Foo
      def define_final
        ObjectSpace.define_finalizer(self, self.class.create_finalizer)
      end
    
      def self.create_finalizer
        proc do |id|
          puts "Running finalizer for #{id}!"
        end
      end
    end
    
  • Use a callable object:

    Example
    class Foo
      class Finalizer
        def call(id)
          puts "Running finalizer for #{id}!"
        end
      end
    
      def define_final
        ObjectSpace.define_finalizer(self, Finalizer.new)
      end
    end
    

Note that finalization can be unpredictable and is never guaranteed to be run except on exit.