@@ -1709,63 +1709,68 @@ rb_gc_copy_finalizer(VALUE dest, VALUE obj)
17091709
17101710/*
17111711 * call-seq:
1712- * ObjectSpace.define_finalizer(obj, aProc=proc())
1712+ * ObjectSpace.define_finalizer(obj) {|id| ... } -> array
1713+ * ObjectSpace.define_finalizer(obj, finalizer) -> array
17131714 *
1714- * Adds <i>aProc</i> as a finalizer, to be called after <i>obj</i>
1715- * was destroyed. The object ID of the <i>obj</i> will be passed
1716- * as an argument to <i>aProc</i>. If <i>aProc</i> is a lambda or
1717- * method, make sure it can be called with a single argument.
1715+ * Adds a new finalizer for +obj+ that is called when +obj+ is destroyed
1716+ * by the garbage collector or when Ruby shuts down (which ever comes first).
17181717 *
1719- * The return value is an array <code>[0, aProc]</code>.
1718+ * With a block given, uses the block as the callback. Without a block given,
1719+ * uses a callable object +finalizer+ as the callback. The callback is called
1720+ * when +obj+ is destroyed with a single argument +id+ which is the object
1721+ * ID of +obj+ (see Object#object_id).
17201722 *
1721- * The two recommended patterns are to either create the finaliser proc
1722- * in a non-instance method where it can safely capture the needed state,
1723- * or to use a custom callable object that stores the needed state
1724- * explicitly as instance variables.
1723+ * The return value is an array <code>[0, callback]</code>, where +callback+
1724+ * is a Proc created from the block if one was given or +finalizer+ otherwise.
17251725 *
1726- * class Foo
1727- * def initialize(data_needed_for_finalization)
1728- * ObjectSpace.define_finalizer(self, self.class.create_finalizer(data_needed_for_finalization))
1729- * end
1726+ * Note that defining a finalizer in an instance method of the object may prevent
1727+ * the object from being garbage collected since if the block or +finalizer+ refers
1728+ * to +obj+ then +obj+ will never be reclaimed by the garbage collector. For example,
1729+ * the following script demonstrates the issue:
17301730 *
1731- * def self.create_finalizer(data_needed_for_finalization)
1732- * proc {
1733- * puts "finalizing #{data_needed_for_finalization}"
1734- * }
1731+ * class Foo
1732+ * def define_final
1733+ * ObjectSpace.define_finalizer(self) do |id|
1734+ * puts "Running finalizer for #{id}!"
1735+ * end
17351736 * end
17361737 * end
17371738 *
1738- * class Bar
1739- * class Remover
1740- * def initialize(data_needed_for_finalization)
1741- * @data_needed_for_finalization = data_needed_for_finalization
1742- * end
1739+ * obj = Foo.new
1740+ * obj.define_final
17431741 *
1744- * def call(id)
1745- * puts "finalizing #{@data_needed_for_finalization}"
1746- * end
1742+ * There are two patterns to solve this issue:
1743+ *
1744+ * - Create the finalizer in a non-instance method so it can safely capture
1745+ * the needed state:
1746+ *
1747+ * class Foo
1748+ * def define_final
1749+ * ObjectSpace.define_finalizer(self, self.class.create_finalizer)
17471750 * end
17481751 *
1749- * def initialize(data_needed_for_finalization)
1750- * ObjectSpace.define_finalizer(self, Remover.new(data_needed_for_finalization))
1752+ * def self.create_finalizer
1753+ * proc do |id|
1754+ * puts "Running finalizer for #{id}!"
1755+ * end
17511756 * end
17521757 * end
17531758 *
1754- * Note that if your finalizer references the object to be
1755- * finalized it will never be run on GC, although it will still be
1756- * run at exit. You will get a warning if you capture the object
1757- * to be finalized as the receiver of the finalizer.
1759+ * - Use a callable object:
1760+ *
1761+ * class Foo
1762+ * class Finalizer
1763+ * def call(id)
1764+ * puts "Running finalizer for #{id}!"
1765+ * end
1766+ * end
17581767 *
1759- * class CapturesSelf
1760- * def initialize(name)
1761- * ObjectSpace.define_finalizer(self, proc {
1762- * # this finalizer will only be run on exit
1763- * puts "finalizing #{name}"
1764- * })
1768+ * def define_final
1769+ * ObjectSpace.define_finalizer(self, Finalizer.new)
17651770 * end
17661771 * end
17671772 *
1768- * Also note that finalization can be unpredictable and is never guaranteed
1773+ * Note that finalization can be unpredictable and is never guaranteed
17691774 * to be run except on exit.
17701775 */
17711776
0 commit comments