(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
Is there a way to do this directly that I'm missing?
How have others handled this situation?
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);
}
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
>
To enable it you should just pass --expose-gc flag.
yours,
anton.
Hi Anton,
Thanks! That is exactly what I'm looking for. For the record, the
flag is --expose_gc.
Cheers,
Ross
Just kidding. Either spelling works.