Garbage collection and Arrays

A

Aaron Patterson

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:

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}" }

Is this a bug? Or is there something I'm missing? Thanks!

--Aaron
 
K

khaines

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:

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}" }

Is this a bug? Or is there something I'm missing? Thanks!

Check the archives of the list for extensive discussion. The upshot is
that it's a problem with this shift() method.


Kirk Haines
 
B

bbiker

Aaron said:

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 :eek:rig_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 :eek:rig_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: []
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top