25

V8's documentation explains how to create a Javascript object that wraps a C++ object. The Javascript object holds on to a pointer to a C++ object instance. My question is, let's say you create the C++ object on the heap, how can you get a notification when the Javascript object is collected by the gc, so you can free the heap allocated C++ object?

postfuturist
  • 22,211
  • 11
  • 65
  • 85
  • The supplied hotlink is (probably long-)dead. A plausible guess at what it might have contained is: https://v8.dev/docs/embed#templates – Ron Burk Sep 28 '20 at 04:40

3 Answers3

23

The trick is to create a Persistent handle (second bullet point from the linked-to API reference: "Persistent handles are not held on a stack and are deleted only when you specifically remove them. ... Use a persistent handle when you need to keep a reference to an object for more than one function call, or when handle lifetimes do not correspond to C++ scopes."), and call MakeWeak() on it, passing a callback function that will do the necessary cleanup ("A persistent handle can be made weak, using Persistent::MakeWeak, to trigger a callback from the garbage collector when the only references to an object are from weak persistent handles." -- that is, when all "regular" handles have gone out of scope and when the garbage collector is about to delete the object).

The Persistent::MakeWeak method signature is:

void MakeWeak(void* parameters, WeakReferenceCallback callback);

Where WeakReferenceCallback is defined as a pointer-to-function taking two parameters:

typedef void (*WeakReferenceCallback)(Persistent<Object> object,
                                      void* parameter);

These are found in the v8.h header file distributed with V8 as the public API.

You would want the function you pass to MakeWeak to clean up the Persistent<Object> object parameter that will get passed to it when it's called as a callback. The void* parameter parameter can be ignored (or the void* parameter can point to a C++ structure that holds the objects that need cleaning up):

void CleanupV8Point(Persistent<Object> object, void*)
{
    // do whatever cleanup on object that you're looking for
    object.destroyCppObjects();
}

Parameter<ObjectTemplate> my_obj(ObjectTemplate::New());

// when the Javascript part of my_obj is about to be collected
// we'll have V8 call CleanupV8Point(my_obj)
my_obj.MakeWeak(NULL, &CleanupV8Point);
Max Lybbert
  • 19,717
  • 4
  • 46
  • 69
  • How do you do that for a Local? I'm trying to do it from within my constructor FunctionTemplate. I can't figure out a syntax that doesn't yell at me. Tried .MakeWeak but that doesn't exist, tried Persistent::New, but it wanted a pointer to my object and my compiler wouldn't let me create a pointer to a local object. – xaxxon Dec 28 '15 at 04:54
  • @xaxxon: I'll be the first to admit that I don't have any experience with the V8 Javascript engine (I happened to be able to find the answer to this question from the documentation six years ago). I **think** the answer to your question is the example on https://developers.google.com/v8/embed?csw=1#dynamic , but it's also possible that you have a question worth asking on its own. – Max Lybbert Dec 28 '15 at 16:12
  • Thanks. I did eventually figure it out. https://code.google.com/p/chromium/codesearch#chromium/src/v8/src/d8.cc&l=1064 starting around line 1400 – xaxxon Dec 28 '15 at 18:46
0

In general, if a garbage-collected language can hold references to resources outside of the language engine (files, sockets, or in your case C++ objects), you should provide a 'close' method to release that resource ASAP, no point waiting until the GC thinks it's worthwhile to destroy your object.

it gets worse if your C++ object is memory-hungry and the garbage-collected object is just a reference: you might allocate thousands of objects, and the GC only sees a few KB's of tiny objects, not enough to trigger collection; while the C++ side is struggling with tens of megabytes of stale objects.

Javier
  • 60,510
  • 8
  • 78
  • 126
  • 3
    That's why there's the function V8::AdjustAmountOfExternalAllocatedMemory()... This way you can tell V8 that your object is hungry... :-) – nalply Feb 28 '10 at 22:37
0

Do all your work in some closed scope (of object or function). Then you can safely remove the C++ object when you went out of scope. GC doesn't check pointers for existence of pointed objects.

Thevs
  • 3,189
  • 2
  • 20
  • 32