On 9/25/07, ara.t.howard <ara.t.howard / gmail.com> wrote:
>
> i don't think i've ever noticed this behaviour:
>
> cfp:~ > cat a.rb
>
> class C
>    def self.count
>      c = 0
>      ObjectSpace.each_object do |object|
>        c += 1 if self === object rescue next
>      end
>      c
>    end
> end
>
> loop do
>    c = nil  ### try with and without this!!!!!!!!!!!!!!
>
>    (2 ** 16).times do
>      c = C.new
>      object_id = c.object_id
>      ObjectSpace.define_finalizer(c){ :nothing }
>    end
>
>    puts "before: #{ C.count }"
>
>    GC.start
>
>    puts "after: #{ C.count }"
>    puts
> end
>
>
>
> run both ways.  notice that, without the prior declaration of c, the
> code leaks like crazy: the finalizer itself holds a reference to the
> object and prevents it being reaped.  i don't think i've ever noticed
> this behavior before.  i understand it - but can this be correct?  it
> seems like you should be able to define a finalizer on any object
> without preventing it from being gc'd!

The usual way to do finalizers is

class C
  def self.finalize(resource)
    lambda{ resource.free }
  end

  def initialize
    @resource = Resource.new
    ObjectSpace.define_finalizer(self, C.finalize(resource))
  end
end

You can't GC the finalizer proc before running it, and you can't
run it if there's a reference to the finalized object somewhere.
Including the finalizer proc.