forcing garbage collection (for tests)

2,938 views
Skip to first unread message

Ross Kinder

unread,
Dec 14, 2010, 1:47:04 PM12/14/10
to v8-u...@googlegroups.com
Hi All,

(I've seen the topic of forcing garbage collection come up a few times
before on the list, but I didn't see anyone talking about this issue)

I've got a program which embeds V8 and I've some some unittests
written which exercise my program and thus V8. To wrap native
objects, I use SetPointerInInternalField() and a wreak reference to
delete the native object when the garbage collector destroys the
javascript object.

This works well for most situations, but in a few cases, I want to
force the underlying native object to be deleted (e.g. to release
resources it holds). I understand that I cannot do this directly with
v8, so I just steal ownership of the native object from the v8::Object
by calling SetPointerInInternalField(..., NULL). This approach works
nicely for me because I happen to know that the v8::Object object will
never be used again in the program.

The problem is that this is tricky, and I'd like my tests to verify
that I've done it correctly. As it stands, I get crashes when garbage
collection runs, which is in the middle of some subsequent test. I'd
love to have a way, just for testing purposes, to force the garbage
collector to run, so that crashes occur in the actual failing test.

Is there a way to do this directly that I'm missing?

How have others handled this situation?

Cheers,

Ross

Stephan Beal

unread,
Dec 14, 2010, 2:00:30 PM12/14/10
to v8-u...@googlegroups.com
On Tue, Dec 14, 2010 at 7:47 PM, Ross Kinder <ro...@kndr.org> wrote:
Is there a way to do this directly that I'm missing?

How have others handled this situation?
 
Hi!

The approach i've taken to this is basically the same as yours. The code is:


i think the one thing i do which you don't mention is the call of ClearWeak() on the Persistent Handle.

Maybe that helps?

Ross Kinder

unread,
Dec 15, 2010, 11:38:13 AM12/15/10
to v8-u...@googlegroups.com
On Tue, Dec 14, 2010 at 11:00 AM, Stephan Beal <sgb...@googlemail.com> wrote:
> On Tue, Dec 14, 2010 at 7:47 PM, Ross Kinder <ro...@kndr.org> wrote:
>>
>> Is there a way to do this directly that I'm missing?
>>
>> How have others handled this situation?
> Hi!
> The approach i've taken to this is basically the same as yours. The code is:
> http://code.google.com/p/v8-juice/source/browse/trunk/src/include/v8/juice/ClassWrap.h?r=1220#1433
> i think the one thing i do which you don't mention is the call of
> ClearWeak() on the Persistent Handle.
> Maybe that helps?

I'm not sure that is actually my current problem, but I can see how it
would be used.

My primary concern is providing a way to isolate unittests from each
other. Here is the (somewhat hackish) solution I came up with, for
feedback/posterity. This appears to solve my problem by causing my
broken dtors to crash in the current test case, rather than a few
tests later when GC finally runs. I call
ForTestingEnsureGarbageCollected() in the tear down of each test case:

void OnGarbageCollected(v8::Persistent<v8::Value> value, void * parameter) {
*reinterpret_cast<bool *>(parameter) = true;
value.Dispose();
}

// static
void ForTestingEnsureGarbageCollected() {
static bool gc_has_run = false;

v8::Context::Scope scope(v8::Context::New());
v8::HandleScope handle_scope;

// Create a dummy object that will be destroyed for sure when the GC runs
v8::Persistent<v8::Object> weakref;
{
v8::HandleScope handle_scope;
v8::Handle<v8::Object> dummy_ob(v8::Object::New());
weakref = v8::Persistent<v8::Object>::New(dummy_ob);
gc_has_run = false;
weakref.MakeWeak(&gc_has_run, &OnGarbageCollected);
}

static const int kMemoryIncrement = 0x10000;
int adjustment = 0;
while (!gc_has_run) {
// via http://create.tpsitulsa.com/wiki/V8/Garbage_Collection
v8::V8::AdjustAmountOfExternalAllocatedMemory(kMemoryIncrement);
adjustment += kMemoryIncrement;

v8::HandleScope handle_scope;
v8::Handle<v8::Object> dummy_ob(v8::Object::New());
}
v8::V8::AdjustAmountOfExternalAllocatedMemory(adjustment * -1);
}

Anton Muhin

unread,
Dec 15, 2010, 11:46:02 AM12/15/10
to v8-u...@googlegroups.com
Ross,

there is GCExtension in v8 which exposes global gc() function (which
trigger garbage collection).

To enable it you should just pass --expose-gc flag.

See src/bootstrapper.cc, Genesis::InstallExtensions and
src/extensions/gc-extension.{h,cc} for more details.

yours,
anton.

> --
> v8-users mailing list
> v8-u...@googlegroups.com
> http://groups.google.com/group/v8-users
>

Stephan Beal

unread,
Dec 15, 2010, 12:54:38 PM12/15/10
to v8-u...@googlegroups.com
On Wed, Dec 15, 2010 at 5:46 PM, Anton Muhin <ant...@chromium.org> wrote:
To enable it you should just pass --expose-gc flag.

Is there a way to determine, from client code, at runtime, whether that option is enabled/available?

Anton Muhin

unread,
Dec 15, 2010, 12:58:52 PM12/15/10
to v8-u...@googlegroups.com
I don't know. One, but not the most elegant approach, would be to
check if property "gc" is present on global object.

yours,
anton.

Ross Kinder

unread,
Dec 15, 2010, 4:02:23 PM12/15/10
to v8-u...@googlegroups.com
On Wed, Dec 15, 2010 at 8:46 AM, Anton Muhin <ant...@chromium.org> wrote:
> there is GCExtension in v8 which exposes global gc() function (which
> trigger garbage collection).
>
> To enable it you should just pass --expose-gc flag.
>
> See src/bootstrapper.cc, Genesis::InstallExtensions and
> src/extensions/gc-extension.{h,cc} for more details.

Hi Anton,

Thanks! That is exactly what I'm looking for. For the record, the
flag is --expose_gc.

Cheers,

Ross

Ross Kinder

unread,
Dec 15, 2010, 4:04:09 PM12/15/10
to v8-u...@googlegroups.com
On Wed, Dec 15, 2010 at 1:02 PM, I wrote:
> For the record, the flag is --expose_gc.

Just kidding. Either spelling works.

Thomas Jansen

unread,
Jan 4, 2011, 8:55:13 PM1/4/11
to v8-users
The garbage collection can be forced from C++ like this:

while(!V8::IdleNotification()) {};

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