File: soft_reference.rb

package info (click to toggle)
ruby-ref 1.0.5%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 332 kB
  • ctags: 186
  • sloc: ruby: 1,107; java: 92; makefile: 2
file content (67 lines) | stat: -rw-r--r-- 2,223 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
module Ref
  # A SoftReference represents a reference to an object that is not seen by
  # the tracing phase of the garbage collector. This allows the referenced
  # object to be garbage collected as if nothing is referring to it.
  #
  # A SoftReference differs from a WeakReference in that the garbage collector
  # is not so eager to reclaim soft references so they should persist longer.
  #
  # === Example usage:
  #
  #   foo = Object.new
  #   ref = Ref::SoftReference.new(foo)
  #   ref.object			# should be foo
  #   ObjectSpace.garbage_collect
  #   ref.object			# should be foo
  #   ObjectSpace.garbage_collect
  #   ObjectSpace.garbage_collect
  #   ref.object			# should be nil
  class SoftReference < Reference
    @@strong_references = [{}]
    @@gc_flag_set = false
    
    # Number of garbage collection cycles after an object is used before a reference to it can be reclaimed.
    MIN_GC_CYCLES = 10
    
    @@lock = SafeMonitor.new
    
    @@finalizer = lambda do |object_id|
      @@lock.synchronize do
        while @@strong_references.size >= MIN_GC_CYCLES do
          @@strong_references.shift
        end
        @@strong_references.push({}) if @@strong_references.size < MIN_GC_CYCLES
        @@gc_flag_set = false
      end
    end
    
    # Create a new soft reference to an object.
    def initialize(obj)
      @referenced_object_id = obj.__id__
      @weak_reference = WeakReference.new(obj)
      add_strong_reference(obj)
    end
    
    # Get the referenced object. If the object has been reclaimed by the
    # garbage collector, then this will return nil.
    def object
      obj = @weak_reference.object
      # add a temporary strong reference each time the object is referenced.
      add_strong_reference(obj) if obj
      obj
    end
    
    private
      # Create a strong reference to the object. This reference will live
      # for three passes of the garbage collector.
      def add_strong_reference(obj) #:nodoc:
        @@lock.synchronize do
          @@strong_references.last[obj] = true
          unless @@gc_flag_set
            @@gc_flag_set = true
            ObjectSpace.define_finalizer(Object.new, @@finalizer)
          end
        end
      end
  end
end