"Kent Dahl" <kentda+news / stud.ntnu.no> schrieb im Newsbeitrag
news:bh8eed$r82$1 / tyfon.itea.ntnu.no...
> Tim Bates wrote:
> > On Mon, Aug 11, 2003 at 09:56:44PM +0900, Robert Klemme wrote:
> >>Your cache implementation is exactly as it should be, but the code
outside
> >>should only hold on to an instance as long as it is needed, typically a
> >>method invocation's duration.  The only thing the outside world should
store
> >>is the id, which is needed to access the instance via the cache.  A
typical
> >>usage pattern looks like this
> >
> > Yes, except that it doesn't work:
> >
> > [tim@zaphod:3 ~/ruby]$ cat weakref_test.rb
> > require 'weakref'
> >
> > o = Object.new
> > q = o
> > o = WeakRef.new(o)
> > ObjectSpace.garbage_collect
> > p o
> > p q
> > q = nil  # o is now the only reference to the object.
> > ObjectSpace.garbage_collect
> > puts o
>
> Playing around I noticed this:
>
> require 'weakref'
> o = WeakRef.new(Object.new)
> puts o.__getobj__             # A
> puts o.__getobj__.to_s        # B
> ObjectSpace.garbage_collect
> puts o
>
> Comment out line A and B in turn. With only B, o gets GC'ed, but not
> with line A.
>
> A wild guess: Parameters to method calls are pushed onto the stack and
> (naturally for efficiency) not cleaned away after the method call has
> ended. Thus the current call frame contains a reference to the
> "unreferenced" object, and you cannot be sure that it will disappear
> until after the call frame has been "popped" from the call stack.
>
> Does that make any sense to someone with knowledge of the Ruby innards?

A WeakRef does not guarantee that an instance is GC'ed as soon as there is
no strong ref any more.  It's the other way round: *if* there is no strong
ref any more, then the instance *might* be GC'ed during a GC cycle.
Introducing another cycle leads to this:

irb(main):001:0> require 'weakref'
=> true
irb(main):002:0>
irb(main):003:0* o = WeakRef.new(Object.new)
=> #<Object:0x2801ca0>
irb(main):004:0> o.__getobj__             # A
=> #<Object:0x2801ca0>
irb(main):005:0> # o.__getobj__.to_s        # B
irb(main):006:0* ObjectSpace.garbage_collect
=> nil
irb(main):007:0> o
=> #<Object:0x2801ca0>
irb(main):008:0> ObjectSpace.garbage_collect
=> nil
irb(main):009:0> o
WeakRef::RefError: Illegal Reference - probably recycled
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:292:in
`output_value'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:149:in `eval_input'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:146:in
`signal_status'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:146:in `eval_input'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:144:in
`each_top_level_
statement'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb/ruby-lex.rb:219:in
`loop'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb/ruby-lex.rb:247:in
`each_t
op_level_statement'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb/ruby-lex.rb:218:in
`catch'

        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb/ruby-lex.rb:218:in
`each_t
op_level_statement'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:144:in `eval_input'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:70:in `start'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:69:in `catch'
        from C:/Programme/Ruby-1.8.0/lib/ruby/1.8/irb.rb:69:in `start'
        from C:/Programme/Ruby-1.8.0/bin/irb:13
Maybe IRB bug!!
irb(main):010:0>

Of course another option is that you might have found a bug in WeakRef / GC,
but I don't assume so in this case.

Regards

    robert