I'm considering using V8 as an embedded JavaScript engine for a project but I'm having trouble figuring out how to manage the lifetime of native C++ objects. This experiment was supposed to demonstrate the Weak Pointer callback.
Near the end of the code below I call v8::Persistent::SetWeak
and install a callback. All I want is to be able to create a demonstration of this callback being called.
I half-heartedly hoped it would be as easy as letting the handles fall out of scope, but the code below doesn't call the callback. I also read somewhere that calling Isolate::IdleNotificationDeadline
might force a garbage collection, but this didn't work either.
How can I demonstrate the weak pointer callback being called? I'd like to write some code that will result in the the cleanup
function being called at some point before the program exits.
I clearly am having trouble understanding how to set this up properly and would appreciate some assistance an an explanation. I'm afraid I just don't get it yet.
My expectation is that it's possible to create a Weak Pointer via a Persistent
handle and that when there are no more handles to an object, the callback will (eventually) be called so that native C++ resources associated with that JavaScript object can be freed.
I'm particularly put off by a comment in the v8.h header file:
NOTE: There is no guarantee as to when or even if the callback is invoked. The invocation is performed solely on a best effort basis. As always, GC-based finalization should not be relied upon for any critical form of resource management!
This makes the entire engine seem useless to me for managing a native object with this mechanism. But I'm confident there's at least some minimal contrived scenario in which the callback is called.
My requirement is that I am able to write some JavaScript to allocate an object that will eventually be freed when there are no more references to it.
foo = createFoo(); // creates a JavaScript object wrapping the native C++ Foo object.
doSomethingWith(foo); // do stuff with the Foo here
foo = null; // make sure there are no more JavaScript handles to the wrapper for the Foo object.
// After this point, I'm hoping V8 will eventually let me know that I can delete the native C++ Foo object
I'm assuming I don't actually have to execute any JavaScript to demonstrate the weak pointer and cleanup mechanism. I was hoping I could just create a Persistent
handle and install the Weak callback then let it go out of scope. I seem to be wrong in that assumption, or I have failed to demonstrate it here.
#include <iostream>
#include "include/libplatform/libplatform.h"
#include "include/v8.h"
class Foo {};
void cleanup(const v8::WeakCallbackInfo<Foo>& data)
{
std::cout << "Weak Callback called" << std::endl;
delete data.GetParameter();
}
int main(int argc, char* argv[]) {
std::cout << "Start..." << std::endl;
v8::V8::InitializeICUDefaultLocation(argv[0]);
v8::V8::InitializeExternalStartupData(argv[0]);
std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
v8::V8::InitializePlatform(platform.get());
v8::V8::Initialize();
// Create a new isolate and make it the current one
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = v8::ArrayBuffer::Allocator::NewDefaultAllocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, v8::ObjectTemplate::New(isolate));
v8::Context::Scope context_scope(context);
v8::Local<v8::Object> obj = v8::ObjectTemplate::New(isolate)->NewInstance(context).ToLocalChecked();
v8::Persistent<v8::Object> persistent;
persistent.Reset(isolate, obj);
persistent.SetWeak(new Foo(), cleanup, v8::WeakCallbackType::kParameter);
}
isolate->IdleNotificationDeadline(1.0);
std::cout << "...Finish" << std::endl;
}
Note: The above code example should be built the same way the hello_world example for V8 is built.