Class: Ref::ReferenceQueue

Inherits:
Object
  • Object
show all
Defined in:
lib/ref/reference_queue.rb

Overview

This class provides a simple thread safe container to hold a reference queue. Instances of WeakReference can be added to the queue and as the objects pointed to by those references are cleaned up by the garbage collector, the references will be added to the queue.

The reason for using a reference queue is that it tends to be more efficient than adding individual finalizers to objects and the cleanup code can be handled by a thread outside of garbage collection.

In general, you should create your own subclass of WeakReference that contains the logic needed to complete the cleanup. The object pointed to will have already been cleaned up and the reference cannot maintain a reference to the object.

Example usage:

class MyRef < Ref::WeakReference
  def cleanup
    # Do something...
  end
end

queue = Ref::ReferenceQueue.new
ref = MyRef.new(Object.new)
queue.monitor(ref)
queue.shift                 # = nil
ObjectSpace.garbage_collect
r = queue.shift             # = ref
r.cleanup

Instance Method Summary collapse

Constructor Details

#initializeReferenceQueue

Returns a new instance of ReferenceQueue.



30
31
32
33
34
35
36
37
38
39
40
# File 'lib/ref/reference_queue.rb', line 30

def initialize
  @queue = []
  @references = {}
  @lock = SafeMonitor.new
  @finalizer = lambda do |object_id|
    @lock.synchronize do
      ref = @references.delete(object_id)
      @queue.push(ref) if ref
    end
  end
end

Instance Method Details

#empty?Boolean

Return true if the queue is empty.

Returns:

  • (Boolean)


80
81
82
# File 'lib/ref/reference_queue.rb', line 80

def empty?
  @queue.empty?
end

#monitor(reference) ⇒ Object

Monitor a reference. When the object the reference points to is garbage collected, the reference will be added to the queue.



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ref/reference_queue.rb', line 44

def monitor(reference)
  obj = reference.object
  if obj
    @lock.synchronize do
      @references[reference.referenced_object_id] = reference
    end
    ObjectSpace.define_finalizer(obj, @finalizer)
  else
    push(reference)
  end
end

#popObject

Pull the last reference off the queue. Returns nil if their are no references.



66
67
68
69
70
# File 'lib/ref/reference_queue.rb', line 66

def pop
  @lock.synchronize do
    @queue.pop
  end
end

#push(reference) ⇒ Object

Add a reference to the queue.



57
58
59
60
61
62
63
# File 'lib/ref/reference_queue.rb', line 57

def push(reference)
  if reference
    @lock.synchronize do
      @queue.push(reference)
    end
  end
end

#shiftObject

Pull the next reference off the queue. Returns nil if there are no references.



73
74
75
76
77
# File 'lib/ref/reference_queue.rb', line 73

def shift
  @lock.synchronize do
    @queue.shift
  end
end

#sizeObject

Get the current size of the queue.



85
86
87
# File 'lib/ref/reference_queue.rb', line 85

def size
  @queue.size
end