checking that objects are collected

81 views
Skip to first unread message

Anthony Shipman

unread,
Oct 19, 2008, 7:32:29 PM10/19/08
to v8-u...@googlegroups.com
I've got code to create a JS object that wraps a C++ object.
I'm using a weak pointer from the C++ object to the JS object to detect when
the JS object is collected so that I can delete the C++ object.

I can't yet demonstrate that the C++ object is deleted. I wrote a simple loop
in JS

function f()
{
for (i = 0; i < 1000; ++i)
{
new jfx.ByteBuffer();
}
}

and run v8 with the flags
--log_handles --gc_interval=10 --trace_gc --gc_global

I get debugging messages

constructed byte buffer 0x8a1e0e8, isWeak = 1
0x8a1e0e8: isWeak=1, isNearDeath=0
Mark-sweep 0.4 -> 0.4 MB, 20 ms.
constructed byte buffer 0x8a440f8, isWeak = 1
0x8a1e0e8: isWeak=1, isNearDeath=0

The weak pointers are never marked as NearDeath.

From v8.log I get

GlobalHandle::MakeWeak,0x8a538b4
GlobalHandle::MakeWeak,0x8a538b4
markcompact,begin,2,797574,1224457984667
markcompact,end,2,809572,1224457984679
scavenge,begin,2,809572,1224457984679
scavenge,end,2,810572,1224457984679
GlobalHandle::MakeWeak,0x8a538b4

so you'd think that if the JS objects were no longer referenced then I would
see them deleted.

So what do I have to do to generate garbage in scripts if the above for-loop
doesn't do it.

--
Anthony Shipman Mamas don't let your babies
a...@iinet.net.au grow up to be outsourced.

Pete Gontier

unread,
Oct 19, 2008, 8:16:59 PM10/19/08
to v8-u...@googlegroups.com
I had to do two things:

  • re-assign the variable holding my test object to another (delete was not enough)
  • collect the garbage explicitly

static void CollectGarbage (void)
{
syslog (LOG_NOTICE, "collecting garbage");

TryCatch tryCatch;

Local <Context> currentContext (Context::GetCurrent ( ));
Local <Object> global (currentContext->Global ( ));
Local <Value> gc (global->Get (String::New ("gc")));
Local <Function> gcFunc (Function::Cast (*gc));

(void) gcFunc->Call (global, 0, NULL);

syslog (LOG_NOTICE, "collected garbage");
}

(This depends on the --expose-gc flag.)

Interestingly, I don't seem to use tryCatch, having declared it. Hmmm.

Pete Gontier <http://pete.gontier.org/>


Anthony Shipman

unread,
Oct 20, 2008, 11:34:41 AM10/20/08
to v8-u...@googlegroups.com, Pete Gontier
On Mon, 20 Oct 2008 11:16:59 am Pete Gontier wrote:
> I had to do two things:
>
> re-assign the variable holding my test object to another (delete was  
> not enough)
> collect the garbage explicitly

I can't make it collect my object even when doing

for (i = 0; i < 1000; ++i)
{

var x = new jfx.ByteBuffer();
x = 0;
gc();
}

and flags
--new_space_size=65536 --old_space_size=2500000 --expose_gc --log_handles --trace_gc --gc_global

Anthony Shipman

unread,
Oct 20, 2008, 12:39:57 PM10/20/08
to v8-u...@googlegroups.com, Pete Gontier
On Tue, 21 Oct 2008 02:34:41 am Anthony Shipman wrote:
> On Mon, 20 Oct 2008 11:16:59 am Pete Gontier wrote:
> > I had to do two things:
> >
> > re-assign the variable holding my test object to another (delete was  
> > not enough)
> > collect the garbage explicitly
>
> I can't make it collect my object even when doing
>
> for (i = 0; i < 1000; ++i)
> {
> var x = new jfx.ByteBuffer();
> x = 0;
> gc();
> }
>
> and flags
> --new_space_size=65536 --old_space_size=2500000 --expose_gc --log_handles
> --trace_gc --gc_global

Ignore this. I've got it going.

At one point I was getting a segmentation violation because I wrote

wrap->jsObject_ = Persistent<Object>(args.This());
instead of
wrap->jsObject_ = Persistent<Object>::New(args.This());

I wonder what the use of the first constructor is?

I've also got dumb syntax error messages e.g. writing
for (int i = 0; i < 10; ++i)
{
}
gives me
-------------
<unknown>:146: Uncaught SyntaxError: Unexpected identifier


#
# Fatal error in src/handles-inl.h, line 45
# CHECK(location_ != __null) failed
#

Aborted
-------------
where 146 is not a valid line number.

Pete Gontier

unread,
Oct 20, 2008, 10:13:53 PM10/20/08
to v8-users
On Oct 20, 2008, at 9:39 AM, Anthony Shipman wrote:

I've got it going.

Excellent.

At one point I was getting a segmentation violation because I wrote 

wrap->jsObject_ = Persistent<Object>(args.This());
instead of
wrap->jsObject_ = Persistent<Object>::New(args.This());

I wonder what the use of the first constructor is?

I, too, have wondered this.

Victor Grishchenko

unread,
Oct 21, 2008, 3:47:58 AM10/21/08
to v8-u...@googlegroups.com
On Oct 21, 2008, at 4:13 AM, Pete Gontier wrote:

At one point I was getting a segmentation violation because I wrote 

wrap->jsObject_ = Persistent<Object>(args.This());
instead of
wrap->jsObject_ = Persistent<Object>::New(args.This());

I wonder what the use of the first constructor is?

I, too, have wondered this.

Me too

--

V

Christian Plesner Hansen

unread,
Oct 21, 2008, 3:57:58 AM10/21/08
to v8-u...@googlegroups.com
> wrap->jsObject_ = Persistent<Object>(args.This());
> instead of
> wrap->jsObject_ = Persistent<Object>::New(args.This());
>
> I wonder what the use of the first constructor is?

Persistent handles automatically convert to plain Handles so you can do

Persistent<Object> obj = ...;
Handle<Object> hnd = obj;

This means that you may have a Handle value that you know is a
persistent handle. In that case the first constructor can be used to
"cast" the handle back to a persistent handle

Persistent<Object> re_obj = Persistent<Object>(hnd);

Unfortunately the constructor does not verify that the handle being
converted is a persistent handle, otherwise that would have caught the
issue with your code.


-- Christian

Pete Gontier

unread,
Oct 21, 2008, 9:08:17 PM10/21/08
to v8-u...@googlegroups.com
Makes sense. I would recommend three things for this constructor:

  • in a debug build, assert it's been passed a persistent handle
  • declare it 'explicit' to make it less likely to be used by accident
  • add a comment explaining the situation

Sound right? Time to file a bug?

Pete Gontier <http://pete.gontier.org/>

Christian Plesner Hansen

unread,
Oct 22, 2008, 1:07:48 AM10/22/08
to v8-u...@googlegroups.com
> in a debug build, assert it's been passed a persistent handle

We wanted to add this but haven't been able to come up with a good
model for checking whether a handle is persistent or not. All we see
at the point where the cast takes place is a single pointer value and
there is currently no way to know whether that pointer comes from a
handle scope or a persistent handle.

> declare it 'explicit' to make it less likely to be used by accident

It already is.

> add a comment explaining the situation

Yes, I'll do that.

Adam Nichols

unread,
Oct 22, 2008, 4:15:35 PM10/22/08
to v8-u...@googlegroups.com
To detect persistence, couldn't you just add a member in the base class which returns an identifier and override that in the child class?  For example, the base class might return an empty string when getClassType() is called, where a Persistent would return "Persistent" with the same function call.  Naturally, these values would be set in the constructors and would not be public.  If there's no concern for additional handles in the future, it could even be isBase() which returns a boolean.

--Adam
Reply all
Reply to author
Forward
0 new messages