Force GC for Ruby BOM
I am working on a project where I will manage a bunch of objects created by an external dll. I now start with my Scope class, which implements a patter to store the memory of other "issue" objects. Therefore, I need to call the release method on every reference that the Scope object will maintain when the Scope object is destroyed. This is my code:
module ServiceBus
class Scope
def initialize
@releaseables = []
ObjectSpace.define_finalizer(self, self.class.finalize(@releaseables))
end
def self.finalize(releaseables)
proc { releaseables.each { |obj| obj.release } }
end
def add_obj(obj)
raise "#{self.class} only support releasbles objects" unless obj.respond_to?(:release)
@releaseables << obj
end
end
end
and my spec:
subject(:subject) { ServiceBus::Scope.new }
context "obj respons_to release" do
let(:obj) do
obj = double("ReleaseableObject")
allow(obj).to receive(:release)
obj
end
it "success" do
subject.add_obj obj
end
it "call invoke for all added objects" do
other_obj = double("ReleaseableObject")
allow(other_obj).to receive(:release)
subject.add_obj obj
subject.add_obj other_obj
subject = nil
GC.start
expect(other_obj).to have_received(:release)
expect(other_obj).to have_received(:release)
end
end
This doesn't work because finalization is never done before waiting. How to force GC to destroy object object.
Thanks in advance!
source to share
As far as I know, this is not possible. Implementing a concrete Ruby implementation allows you to decide whether and when objects are actually destroyed. Since garbage collection is implementation specific, there are no guarantees. This, unfortunately, means that finalizers will never be called. However, I think the spec might as well just test the finalizer in isolation. In other words, when you manually trigger the GC, you can manually trigger the finalizer and test its effects.
source to share