From: Charles Oliver Nutter Date: 2009-10-30T02:07:13+09:00 Subject: DRbIdConv without _id2ref As mentioned in a previous thread on ruby-talk, we are looking to remove ObjectSpace_id2ref from JRuby. Matz explained that it was added to support WeakRef, for which we have our own (Java-based) implementation. Supporting it on the JVM (or any VM where objects move in memory) is rather expensive. The only place in stdlib that uses _id2ref_ is this class in drb/drb.rb: class DRbIdConv # Convert an object reference id to an object. # # This implementation looks up the reference id in the local object # space and returns the object it refers to. def to_obj(ref) ObjectSpace._id2ref(ref) end # Convert an object into a reference id. # # This implementation returns the object's __id__ in the local # object space. def to_id(obj) obj.nil? ? nil : obj.__id__ end end I have come up with a possible replacement for this that uses WeakRef. I'd like a few more eyes on it. It's not concurrency-safe, which might be a good addition. The 'clean' method is also not very efficient, but Ruby's WeakRef doesn't have the notion of a reference queue you can poll cheaply. Adding finalizers would be a heavy-weight way to add support for a reference queue. Here's the code I've come up with (plus a "require 'weakref'" near the top of drb/drb.rb): class DRbIdConv def initialize @id2ref = {} end # Convert an object reference id to an object. # # This implementation looks up the reference id in the local object # space and returns the object it refers to. def to_obj(ref) _get(ref) end # Convert an object into a reference id. # # This implementation returns the object's __id__ in the local # object space. def to_id(obj) obj.nil? ? nil : _put(obj) end def _clean dead = [] @id2ref.each {|id,weakref| dead << id unless weakref.weakref_alive?} dead.each {|id| @id2ref.delete(id)} end def _put(obj) _clean @id2ref[obj.__id__] = WeakRef.new(obj) obj.__id__ end def _get(id) weakref = @id2ref[id] if weakref result = weakref.__getobj__ rescue nil if result return result else @id2ref.delete id end end nil end private :_clean, :_put, :_get end And here is a test for it: require 'test/unit' require 'drb' require 'java' class TestWeakDrbIdConv < Test::Unit::TestCase def test_weak_drb_id_conv conv = DRb::DRbIdConv.new obj_ary = [] id_ary = [] # populate 100.times do obj = Object.new obj_ary << obj id_ary << conv.to_id(obj) end # confirm they're there id_ary.each do |id| assert conv.to_obj(id) end # dereference objects and force GC obj_ary = nil 2.times {java.lang.System.gc} # confirm they're gone id_ary.each do |id| assert !conv.to_obj(id) end end end - Charlie