From: "headius (Charles Nutter)" Date: 2012-04-17T18:09:07+09:00 Subject: [ruby-core:44405] [ruby-trunk - Feature #4168] WeakRef is unsafe to use in Ruby 1.9 Issue #4168 has been updated by headius (Charles Nutter). A video of Bob Lee explaining the various JVM references, and why using finalizers is bad: http://www.youtube.com/watch?v=KTC0g14ImPc ---------------------------------------- Feature #4168: WeakRef is unsafe to use in Ruby 1.9 https://bugs.ruby-lang.org/issues/4168#change-25951 Author: bdurand (Brian Durand) Status: Closed Priority: Normal Assignee: nobu (Nobuyoshi Nakada) Category: lib Target version: 2.0.0 =begin I've found a couple issues with the implementation of WeakRef in Ruby 1.9. 1. WeakRef is unsafe to use because the ObjectSpace will recycle object ids for use with newly allocated objects after the old objects have been garbage collected. This problem was not present in 1.8, but with the 1.9 threading improvements there is no guarantee that the garbage collector thread has finished running the finalizers before new objects are allocated. This can result in a WeakRef returning a different object than the one it originally referenced. 2. In Ruby 1.9 a Mutex is used to synchronize access to the shared data structures. However, Mutexes are not reentrant and the finalizers are silently throwing deadlock errors if they run while new WeakRefs are being created. I've included in my patch a reimplementation of WeakRef called WeakReference that does not extend Delegator. This code is based on the original WeakRef code but has been rewritten so the variable names are a little clearer. It replaces the Mutex with a Monitor and adds an additional check to make sure that the object returned by the reference is the same one it originally referred to. WeakRef is rewritten as a Delegator wrapper around a WeakReference for backward compatibility. I went this route because in some Ruby implementations (like Ruby 1.8), Delegator is very heavy weight to instantiate and creating a collection of thousands of WeakRefs will be slow and use up far too much memory (in fact, it would be nice to either backport this patch to Ruby 1.8 or the delegate changes from 1.9 to 1.8 if possible). I also don't really see the value of having weak references be delegators since is very unsafe to do anything without wrapping the call in a "rescue RefError" block. The object can be reclaimed at any time so the only safe method to be sure you still have it is to create a strong reference to the object at which point you might as well use that reference instead of the delegated methods on the WeakRef. It also should be simpler for other implementations of Ruby like Jruby or Rubinius to map native weak references to a simpler interface. Sample code with WeakReference orig = Object.new ref = WeakReference.new(orig) # ... obj = ref.object if obj # Do something end I also have a version of the patch which just fixes WeakRef to work without introducing a new class, but I feel this version is the right way to go. Also included are unit tests for weak references but the test that checks for the broken functionality is not 100% reliable since garbage collection is not deterministic. I've also included a script that shows the problem in more detail with the existing weak reference implementation. ruby show_bug.rb 100000 # Run 100,000 iterations on the current implementation of WeakRef and report any problems ruby -I. show_bug.rb 100000 # Run 100,000 iterations on the new implementation of WeakRef and report any problems =end -- http://bugs.ruby-lang.org/