How to understand why object is not collected?

  • Thread starter Victor \Zverok\ Shepelev
  • Start date
V

Victor \Zverok\ Shepelev

Hi all.

Here's a problem.

I have some object of MyClass with complex "freeing" logic, and I want to
test this logic.
I do:

---------
span = .... #somehow created object

ObjectSpace.define_finalizer(span, proc{p "gc ok"}) #define test finalizer

span.detach #remove object from all of my internal caches, no references
to object should exist

span = nil #remove the last reference to object

GC.start #<===HERE the object must be collected and finalized

p "end of code"
---------

I expect:
---
"gc ok"
"end of code"
---

I receive:
---
"end of code"
"gc ok"
---

OK, I suppose there are some references to the object still exists. I want
to know, at least, what number of references still exists (in ideal, I'd
want to know, where they are).
How I can? (except of harcode hacking GC's C code)

Ruby 1.9 (downloaded a week ago), Windows.

Thanks.

V.
 
J

Joel VanderWerf

Victor said:
Hi all.

Here's a problem.

I have some object of MyClass with complex "freeing" logic, and I want to
test this logic.
I do:

---------
span = .... #somehow created object

ObjectSpace.define_finalizer(span, proc{p "gc ok"}) #define test finalizer

span.detach #remove object from all of my internal caches, no references
to object should exist

span = nil #remove the last reference to object

GC.start #<===HERE the object must be collected and finalized

This is probably a situation where GC is being conservative. A simple
example:

class Foo; end

foo = Foo.new
foo = nil

GC.start

p ObjectSpace.each_object(Foo) {} # ==> 1

Probably this means that the Foo instance pointer is still visible
somewhere in the local frame.

But that doesn't mean that there is a leak:

class Foo; end

10.times do
Foo.new
end

GC.start

p ObjectSpace.each_object(Foo) {} # ==> 1

In my experience, it's hard to write precise unit tests for GC behavior,
and you end up with some fuzziness. The important property of GC is
really the asymptotic behavior.
 
V

Victor \Zverok\ Shepelev

From: Joel VanderWerf [mailto:[email protected]]
Sent: Saturday, October 28, 2006 10:52 PM
This is probably a situation where GC is being conservative. A simple
example:

class Foo; end

foo = Foo.new
foo = nil

GC.start

p ObjectSpace.each_object(Foo) {} # ==> 1

OK, I've got it.
In my experience, it's hard to write precise unit tests for GC behavior,
and you end up with some fuzziness. The important property of GC is
really the asymptotic behavior.

Just for now, I need no precise unit test. I just want to know, would the
objects of MyClass collected in principle. Can I achieve the goal somehow?

V.
 
E

Eero Saynatkari

--yahdd2r5OMEJJ+pI
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi all.
=20
Here's a problem.
=20
I have some object of MyClass with complex "freeing" logic, and I want to
test this logic.
<snip />=20

Hard to say what is going wrong but the solution is simple. Whenever
you have a resource that must be released, do it explicitly. The way
this is usually implemented is either:

f =3D File.open 'foo'
puts f.read
f.close

Or, more conveniently

File.open('foo') {|f| puts f.read}

The block-form uses ensure to make sure the file handle gets closed.

--yahdd2r5OMEJJ+pI
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (FreeBSD)

iD8DBQFFQ7rR7Nh7RM4TrhIRAhX7AKCsmDzd6YaBLK2PbYY/e3DgmUnJLwCfbi0D
pwot24z9lJSVP0kb+WNM+Rw=
=wGC0
-----END PGP SIGNATURE-----

--yahdd2r5OMEJJ+pI--
 
V

Victor \Zverok\ Shepelev

From: Eero Saynatkari [mailto:[email protected]]
Sent: Saturday, October 28, 2006 11:20 PM
Hard to say what is going wrong but the solution is simple. Whenever
you have a resource that must be released, do it explicitly. The way
this is usually implemented is either:

f = File.open 'foo'
puts f.read
f.close

Or, more conveniently

File.open('foo') {|f| puts f.read}

The block-form uses ensure to make sure the file handle gets closed.

I know this (I was C++ guy foe many years, so RAII is my breath), but can't
use.
My objects are HTML DOM elements and I want to be sure they are GC'd when
detached from DOM and have no other references.

V.
 
J

Joel VanderWerf

Victor said:
From: Joel VanderWerf [mailto:[email protected]]
Sent: Saturday, October 28, 2006 10:52 PM
This is probably a situation where GC is being conservative. A simple
example:

class Foo; end

foo = Foo.new
foo = nil

GC.start

p ObjectSpace.each_object(Foo) {} # ==> 1

OK, I've got it.
In my experience, it's hard to write precise unit tests for GC behavior,
and you end up with some fuzziness. The important property of GC is
really the asymptotic behavior.

Just for now, I need no precise unit test. I just want to know, would the
objects of MyClass collected in principle. Can I achieve the goal somehow?

What about creating a lot of them in a loop, without keeping references?
Then I would expect GC to leave at most one instance.
 
V

Victor \Zverok\ Shepelev

From: Joel VanderWerf [mailto:[email protected]]
Sent: Saturday, October 28, 2006 11:26 PM
Victor said:
From: Joel VanderWerf [mailto:[email protected]]
Sent: Saturday, October 28, 2006 10:52 PM
This is probably a situation where GC is being conservative. A simple
example:

class Foo; end

foo = Foo.new
foo = nil

GC.start

p ObjectSpace.each_object(Foo) {} # ==> 1

OK, I've got it.
In my experience, it's hard to write precise unit tests for GC behavior,
and you end up with some fuzziness. The important property of GC is
really the asymptotic behavior.

Just for now, I need no precise unit test. I just want to know, would the
objects of MyClass collected in principle. Can I achieve the goal
somehow?

What about creating a lot of them in a loop, without keeping references?
Then I would expect GC to leave at most one instance.

They can't be created by .new, they created in correspondence to some HTML
DOM by C extension.
Problem already solved by the trick:

--
def test
span = ....
ObjectSpace.define_finalizer(span, proc{p "gc ok"})
span.detach
span = nil
end

test

GC.start

p "end of code"
--

Output corresponds to my expectations (gc ok => end of code)

Thanks for your help!

V.
 

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,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top