V8/Persistent Handles
From Create Wiki
Persistent handles are persistent. They act much like a C++ pointer, in some ways. After you create the handle, it will not go away until you specifically tell it to.
Contents |
Example
//like Value *value = new String("Hello, World"); Persistent<Value> value = Persistent<Value>::New(String::New("Hello, World")); //like delete value value.Dispose(); //like value=NULL; value.Clear();
A more accurate comparison, however, might be to compare Persistent handles to pointers to smart pointers:
//create a string, like String *string = new String(); Handle<String> string = String::New("Hello, World"); //create a pointer to it, like, StringPtr *wrapper = new StringPtr(string); //where StringPtr is a smart pointer type. Persistent<Value> value = Persistent<Value>::New(string); //like deleting StringPtr (which, if it is the only pointer to string, deletes //the string) value.Dispose(); //like StringPtr = NULL value.Clear();
Uses
It is pretty easy to see some potential uses. Persistent handles, because they are persistent, do not need handle scopes. When a handle scope goes out of scope, the persistent handle will persist.
This allows you to store a persistent handle in a class member, for instance:
class MyClass { void storeObject() { HandleScope handle_scope; //BAD BAD: when handle_scope exits, so will the string. myObject = String::New("Hello, World!"); //GOOD: Because it is persistent, it will not get destroyed. myObject = Persistent<String>::New(String::New("Hello, World")); } Handle<Object> myObject; };
Caching Obects
You can use this method to cache C++ objects you have wrapped for JavaScript, allowing re-use of the same wrapper. For instance:
class Point { public: double x, double y; }; std::map<Point *, Persistent<Object> > jsPoints;
Each time you send the point to JavaScript, you would first check to see if you have already done so:
Handle<Object> wrapPoint(Point *point) { HandleScope handle_scope; if (jsPoints.count(point) > 0) return jsPoints[point]; //... some code to create the object goes here //create a persistent pointer to the object Persistent<Object> ptr = Persistent<Object>::New(object); //add it to the map jsPoints[point] = ptr; //return return handle_scope.Close(object); }
Weak Handles
So, you can keep an object from being garbage collected by keeping a persistent reference to it. Great!
Except that, now, you are in a bit of a catch-22. That object won't be destroyed until there are no references, but until the object is destroyed, you probably are not going to want to remove your persistent reference.
What you really need is for that Persistent handle of yours to not really count in garbage collection. You need, when garbage collection occurs, to be notified when there are no references to the object that are not your Persistent handle that should not really be counted. You kind of need the persistent handle to be weaker than the other handles, to not be considered as strongly.
This feature is built in, via a function named MakeWeak. MakeWeak, a member function of Persistent handles, will mark your Persistent handle as being weak. And, when garbage collection occurs, if the only references to an object are weak, a callback function you supply will be called.
For example, a function to wrap a point might look something like this:
Handle<Object> wrapPoint(Point *pointToWrap) { //enter a handle scope HandleScope handle_scope; //store the wrappers in a map so that we don't double-delete. It's like double-dipping, //but seven times worse. if (jsPoints.count(pointToWrap) > 0) return jsPoints[pointToWrap]; //create a new point instance and point to it with a persistent handle Persistent<Object> point_instance = Persistent<Object>::New(point_templ->NewInstance()); /* MAKE THE HANDLE WEAK */ //the first object is a data item we get control of that will be passed //to the callback. point_instance.MakeWeak(pointToWrap, weakPointCallback); //add it to the map jsPoints[pointToWrap] = point_instance; //set that internal field point_instance->SetInternalField(0, External::New(pointToWrap)); //to prevent the point_instance from being destroyed when its //scope handle_scope is, use the Close() function return handle_scope.Close(point_instance); } /* THE CALLBACK FUNCTION */ void weakPointCallback(Persistent<Value> object, void *parameter) { Point *point = static_cast<Point *> (parameter); //remove it from the map jsPoints.erase(point); //javascript no longer uses the object //if we are certain C++ isn't using it, we can just destroy it here. delete point; //clear the reference to it object.Dispose(); object.Clear(); }