Bug #1392
closedObject#extend leaks memory on Ruby 1.9.1
Description
=begin
A few bytes are leaked every time Object#extend is called, here is a sample 1.9.1 script
This code is Ruby 1.9.x and above only¶
@extend = ARGV[0]
module BetterHash
def blabla
end
end
unless @extend
class Hash
include BetterHash
end
end
t = Time.now
1_000_000.times do
s = {}
s.extend BetterHash if @extend
end
after = Time.now - t
puts "done with #{GC.count} gc runs after #{after} seconds"
sleep # so that it doesn't exit before we check the memory
more details here :
http://oldmoe.blogspot.com/2009/04/objectextend-leaks-memory-on-ruby-191.html
oldmoe
=end
Files
Updated by matz (Yukihiro Matsumoto) over 15 years ago
- Status changed from Open to Rejected
=begin
=end
Updated by rogerdpack (Roger Pack) over 15 years ago
=begin
I think you can tell if it was a leak by running a loop
loop do
s = {}
s.extend BetterHash if @extend
end
If this eats up all memory in the system then it's a leak. [on mine it stays constant at 4MB].
That doesn't mean to say there's no bugs in there, though--it may be the case that you're using up the entire freelist each time, without ever passing the malloc_limit, which means that your heap total size will get bigger and bigger and bigger...not sure though.
Compiling 1.9 with the GC stats turned on might help.
Cheers!
-=r
=end
Updated by MiiJaySung (Jason Earl) almost 15 years ago
=begin
I've just tried the code above with Ruby 1.9.2 Preview 1 and the current trunk.
I can confirm that this doing
./ruby leak_test.rb LEAK
on the above versions appears to leak memory as ps aux / top reports a 0.8% memory utilization by the time the script has finished running. The memory usage goes up gradually as the program runs. Once the program has hit the sleep command, the memory usage does not go down, even if a GC.start call has been inserted directly above to coerce the Ruby VM to clean up.
Running this under the current 1.8.8 snapshot does not to this, and the memory usage remains constant throughout. Likewise not passing any arguments (so extend is not called) also keeps the memory usage constant under both 1.8.x and 1.9.x branches tested on my system.
I am running an a 64 bit (x64) bit rather than a 32bit (x86) build.
=end
Updated by MiiJaySung (Jason Earl) almost 15 years ago
=begin
And just to confirm, using an indefinite loop like Roger points out makes my Ruby process grow continuously. After about 6-8 minutes my Ruby process had grown to 12% of memory usage and showed no sign of going down.
=end
Updated by rogerdpack (Roger Pack) almost 15 years ago
=begin
yeah I can confirm this
loop do
Module.new.clone
end
leaks with 1.9.1p376
but doesn't seem to leak for me with trunk. What script are you using exactly?
-r
=end
Updated by MiiJaySung (Jason Earl) almost 15 years ago
=begin
My trunk build is: ruby 1.9.2dev (2010-01-27 trunk 26434) [x86_64-linux]
Your clone code above doesn't leak either for me.
However both of these simplified scenarios leak:
./ruby -e 'loop { Class.new.send :include, Module.new }'
./ruby -e 'loop { Module.new.extend Module.new }'
While I'm no C guru, I'm guessing the issue will be relating to include_class_new in class.c or at least it doesn't look like a garbage collection issue given that your clone seems OK.
=end
Updated by wanabe (_ wanabe) almost 15 years ago
- File free_eclass.patch free_eclass.patch added
- Status changed from Rejected to Open
=begin
I wrote a patch for this issue.
Unless any objections, I will commit later.
=end
Updated by MiiJaySung (Jason Earl) almost 15 years ago
=begin
Thanks for the quick patch. It certainly seems to do the trick.
=end
Updated by wanabe (_ wanabe) almost 15 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
=begin
This issue was solved with changeset r26515.
Muhammad, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
=end
Updated by rogerdpack (Roger Pack) almost 15 years ago
=begin
Thanks for fixing this. Seems to now not leak for this version.
ruby 1.9.2dev (2010-02-01 trunk 26538) [i386-mingw32]
=end