From: bbiker Date: 2007-01-14T15:25:06+09:00 Subject: Re: Garbage collection and Arrays Aaron Patterson wrote: > On Fri, Jan 12, 2007 at 04:05:55PM +0900, Gregory Brown wrote: > > On 1/12/07, Aaron Patterson wrote: > > >Hi, I seem to be running in to some garbage collection weirdness. > > >Hopefully someone will have some insight for me.... My sample script > > >seems to leak Strings when I use shift on an Array, but not pop: > > > > http://recursive.ca/hutch/index.php?p=361 > > > > Thanks! > > -- > Aaron Patterson > http://tenderlovemaking.com/ The workaround to eliminate leakage with array.shift works except that shift no longer returns the shifted element and instead returns nil The following class allows shift to work normally without the leakage ... I know it is only a temporary work around until the ruby developers get around to fix the c code #### Array#shift ############### class Array alias :orig_shift :shift def shift return nil if self.empty? ret = self[0] self[0] = nil self.orig_shift return ret end end ###### code to show that the leakage has been eliminated separator = "---" o_count = Hash.new(0) GC.start ObjectSpace.each_object { |o| o_count[o.class] += 1 } o_count.sort_by { |k,v| -v}.each { |k,v| puts "#{k}: #{v}" } o_count = nil puts separator array = [] 10.times { array << "foo" } 10.times { array.pop } # Change this to shift to see a leak o_count = Hash.new(0) GC.start ObjectSpace.each_object { |o| o_count[o.class] += 1 } o_count.sort_by { |k,v| -v}.each { |k,v| puts "#{k}: #{v}" } array = nil o_count = nil puts separator array = [] 10.times { array << "foo" } 10.times { array.shift } # Change this to shift to see a leak o_count = Hash.new(0) GC.start ObjectSpace.each_object { |o| o_count[o.class] += 1 } o_count.sort_by { |k,v| -v}.each { |k,v| puts "#{k}: #{v}" } __END__ ####### test results only pertinent data shown NEW shift method before pop after pop before shift after shift String: 1746 1764 1764 Array: 70 71 72 OLD shift methed -- Class Array commented out before pop after pop before shift after shift String: 1746 1764 1774 Array: 70 71 72 ################## code to show that Array#shift behaves as described in the ri documentation class Array alias :orig_shift :shift def shift return nil if self.empty? ret = self[0] self[0] = nil self.orig_shift return ret end end a = (1..5).to_a 1.upto(10) do |i| x = a.shift puts "#{i}: \tx: #{x.inspect} \ta: #{a.inspect}" end __END__ 1: x: 1 a: [2, 3, 4, 5] 2: x: 2 a: [3, 4, 5] 3: x: 3 a: [4, 5] 4: x: 4 a: [5] 5: x: 5 a: [] 6: x: nil a: [] 7: x: nil a: [] 8: x: nil a: [] 9: x: nil a: [] 10: x: nil a: []