1

Is it possible to remove objects from an array/hash which is only referenced from this array/hash?

Example of what I am looking for:

some_array.reject!{|elm| ObjectSpace.only_one_reference_to?(elm)}

I am making a script which seem to be growing quickly in the ram. The reason why is is a long-living array which keeps obsolete objects around event though it does not need to.

The problem is essentially this:

@@long_living_array = []
class Foo
    def initialize
        @@long_living_array << self
    end
end

a = Foo.new()
b = Foo.new()
a = nil
#Here is the problem, a sticks around in @@long_living_array, even though it does not really need to be there.

Thus, my real task is to iterate over the @@long_living_array and remove any objects which is only referenced from this array. (And yes, I do need the array.)


I believe it could be solved if I was able to find all references to an object, and then remove the object if the reference in the array is the only one. Thus I have been looking for something along the lines of

a = Foo.new
all_references_to_a = ObjectSpace.get_all_references(a)

I have found this article which seems to do something similar, but it is a patch to Ruby itself (some C files) so it is not possible for me to use.

Automatico
  • 12,420
  • 9
  • 82
  • 110

1 Answers1

2

Instead of storing the object itself, you could store a WeakRef. It allows the referenced object to be garbage-collected:

require 'weakref'

@@long_living_array = []

class Foo
  def initialize
    @@long_living_array << WeakRef.new(self)
  end
end

a = Foo.new
b = Foo.new
@@long_living_array.count
#=> 2

a = nil                                       # reassign 'a'
GC.start                                      # start the garbage collector
@@long_living_array.keep_if(&:weakref_alive?) # remove GC'ed objects

@@long_living_array.count
#=> 1
Stefan
  • 109,145
  • 14
  • 143
  • 218