Skip to content

Instantly share code, notes, and snippets.

@Asher-
Created August 25, 2010 03:08
Show Gist options
  • Save Asher-/548773 to your computer and use it in GitHub Desktop.
Save Asher-/548773 to your computer and use it in GitHub Desktop.
require 'pp'
class Hash::Weak < Hash
def []( key )
# get the stored ID - a FixNum, not an object reference to our weak-referenced object
obj_id = super( key.to_sym )
# theoretically this should cause non-referenced objects to get cleaned up
# so long as nothing looks like a pointer or reference to it
ObjectSpace.garbage_collect
# now get our object from ID
# if it had no references it should have been GC'd and we should get an
# rb_eRangeError "is not id value" (expected) or "is recycled object" (possible)
obj = ObjectSpace._id2ref( obj_id )
return obj
end
def []=( key, object )
# FixNum have a constant ID for value, so can't be copied and can't be garbage collected
# so object.__id__ cannot be a reference to a child of object and therefore cannot prevent
# garbage collection on the object
super( key.to_sym, object.__id__ )
end
end
##################################################
weak_hash = Hash::Weak.new
class TestClass
end
test_object = TestClass.new
puts 'storing test object'
weak_hash[ :key ] = test_object
puts 'hash now contains object id: ' + weak_hash.pretty_inspect
print 'retrieving stored test object from hash (should work/be non-nil): '
valid_key = weak_hash[ :key ]
pp valid_key
class AnotherClass
end
puts 'setting variable referring to test object (ID: ' + test_object.__id__.to_s + ') to nil'
test_object = nil
puts 'ID for variable referring to test object is now: ' + test_object.__id__.to_s
print 'getting test object (should fail with rb_eRangeError): '
invalid_key = weak_hash[ :key ]
pp invalid_key
# error - returns valid key
##################################################
# object is created, given an id
# variable is assigned to id
# variable is changed to new object (including nil)
# variable gets the id of new object
# previous reference made by variable remains in object space (no valid references)
# gc starts
# rb_gc_mark calls gc_mark, marks VM instance (#<RubyVM:0x000001008700b8>)
# gc_mark calls gc_mark_children, marks all children of VM
# first, the VM class (RubyVM), and then its children
# then its class instance (#<Class:RubyVM>), and then its children
# then its class instance (#<Class:#<Class:RubyVM>>) and its children
# then its class instance (#<Class:#<Class:Class>>) and its children
# then gc_mark_children calls mark_tbl to mark its table (the class table)
# mark_tbl marks all children of the class table, starting with Class
# Class marks its children, first of all #<Class:Module>
# #<Class:Module> marks its children, first of all #<Class:#<Class:Module>>
# #<Class:#<Class:Module>> marks its children, which includes a table of classes
# mark_tbl marks each of classes, which first includes #<Class:Object>
# #<Class:Object> has a table of entries that it marks, first of all Object
# Object has a table that it marks, first of all its binding context (presumably main first?) #<Binding:0x00000100870068>
# #<Binding:0x00000100870068> marks its children, which calls binding_mark, which calls rb_gc_mark, which calls gc_mark on the Ruby environment: #<RubyVM::Env:0x00000100854bd8>
# #<RubyVM::Env:0x00000100854bd8> marks its children which calls env_mark
# env_mark calls rb_gc_mark_locations on the range covered by the environment's declared memory space, which calls gc_mark_locations
# gc_mark_locations calls mark_locations_array on the space marked by the start and length of environment
# mark_locations_array looks at the environment as an array of long, and calls is_pointer_to_heap on each one
# if (long)slice is the address of a valid pointer on the heap, returns TRUE, which causes gc_mark to be called on the object
#***** object, defined by ID, matches with (long)slice because it has not yet been collected; it is therefore marked as still existing because it has a valid pointer
# => if this were true, no object would ever be garbage collected; so how is any object ever garbage collected?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment