ObjectSpace.define_finalizer and memory leaks

A

ara.t.howard

i don't think i've ever noticed this behaviour:

cfp:~ > cat a.rb

class C
def self.count
c = 0
ObjectSpace.each_object do |object|
c += 1 if self === object rescue next
end
c
end
end

loop do
c = nil ### try with and without this!!!!!!!!!!!!!!

(2 ** 16).times do
c = C.new
object_id = c.object_id
ObjectSpace.define_finalizer(c){ :nothing }
end

puts "before: #{ C.count }"

GC.start

puts "after: #{ C.count }"
puts
end



run both ways. notice that, without the prior declaration of c, the
code leaks like crazy: the finalizer itself holds a reference to the
object and prevents it being reaped. i don't think i've ever noticed
this behavior before. i understand it - but can this be correct? it
seems like you should be able to define a finalizer on any object
without preventing it from being gc'd!

cheers.

a @ http://drawohara.com/
 
I

Ilmari Heikkinen

i don't think i've ever noticed this behaviour:

cfp:~ > cat a.rb

class C
def self.count
c = 0
ObjectSpace.each_object do |object|
c += 1 if self === object rescue next
end
c
end
end

loop do
c = nil ### try with and without this!!!!!!!!!!!!!!

(2 ** 16).times do
c = C.new
object_id = c.object_id
ObjectSpace.define_finalizer(c){ :nothing }
end

puts "before: #{ C.count }"

GC.start

puts "after: #{ C.count }"
puts
end



run both ways. notice that, without the prior declaration of c, the
code leaks like crazy: the finalizer itself holds a reference to the
object and prevents it being reaped. i don't think i've ever noticed
this behavior before. i understand it - but can this be correct? it
seems like you should be able to define a finalizer on any object
without preventing it from being gc'd!

The usual way to do finalizers is

class C
def self.finalize(resource)
lambda{ resource.free }
end

def initialize
@resource = Resource.new
ObjectSpace.define_finalizer(self, C.finalize(resource))
end
end

You can't GC the finalizer proc before running it, and you can't
run it if there's a reference to the finalized object somewhere.
Including the finalizer proc.
 
S

Sylvain Joyeux

it seems like you should be able to define a finalizer on any object
without preventing it from being gc'd!
The only way I am aware of is to use methods ...
ObjectSpace.define_finalizer(obj, &method:)my_finalizer))
 
A

ara.t.howard

The only way I am aware of is to use methods ...
ObjectSpace.define_finalizer(obj, &method:)my_finalizer))

yeah - trying to prevent the closure... smart. i'm not having luck
though:

cfp:~ > cat a.rb
class C
def self.count
c = 0
ObjectSpace.each_object do |object|
c += 1 if self === object rescue next
end
c
end
end

def nothing
end

loop do
#c = nil ### try with and without this!!!!!!!!!!!!!!

(2 ** 16).times do
c = C.new
ObjectSpace.define_finalizer c, &method:)nothing)
end

puts "before: #{ C.count }"

GC.start

puts "after: #{ C.count }"
puts
end


again, if you un-comment the 'c = nil' line it'll work, but avoid the
closure alone doesn't work on my platform. does it work for you?
did i misunderstand your comment perhaps?

thanks alot for the input.

kind regards.

a @ http://drawohara.com/
 
A

ara.t.howard

The only way I am aware of is to use methods ...
ObjectSpace.define_finalizer(obj, &method:)my_finalizer))

working off of you idea of avoiding any new references whatsoever i
came up with this, which is working for me, can others confirm?

cfp:~ > cat a.rb
class C
def self.count
c = 0
ObjectSpace.each_object do |object|
c += 1 if self === object rescue next
end
c
end
end

def finalizer_for object_id
lambda { p [:finalized, object_id] if $DEBUG }
end

loop do
(2 ** 16).times do
c = C.new
finalizer = finalizer_for c.object_id
c.instance_eval do
ObjectSpace.define_finalizer self, &finalizer
end
end

puts "before: #{ C.count }"

GC.start

puts "after: #{ C.count }"
puts
end


thanks for the inspiration!

kind regards.

a @ http://drawohara.com/
 
S

Sylvain Joyeux

Well, I thought I already tried and that it worked fine... But I think I found
the problem ...

define_finalizer does not take any block ! (so, it is normal that it is not
called ;-)) You have to write either the thing Ilmari suggested or remove
the '&' before the method (it works, I just tried it)
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top