Finally I have found the solution.
1. The "alternative" version of constructor jsnative_myobj() should be
used (it is commented out in the code in my previous post above).
2. Persistent handles are created using Persistent::New(). So, the
line
Persistent<Object> obj( objTpl->NewInstance() );
in jsnative_myobj() has to be replaced with the following one:
Persistent<Object> obj = Persistent<Object>::New( objTpl-
>NewInstance() );
With these modifications, the callback RemoveMyObj() gets called at GC
time, so I can go further in using V8.
On 22 фев, 12:31, deadmorous <[email protected]> wrote:
> On 22 фев, 03:17, Alfred Rossi <[email protected]> wrote:> This looks fine to
> me. The garbage collector may not have deemed it
> > worthwhile to collect for whatever reason.
>
> I have prepared a minimal example program, in which gc is forced
> (using v8/gc extension). Still no effect. Here is the code:
> ---- 8< ----
> // main.cpp
>
> #pragma warning (disable:4251) // I'm on Windows and using v8 as a
> dll, ang getting this warning under these conditions
>
> #include <iostream>
> #include "v8.h"
>
> using namespace std;
> using namespace v8;
>
> Handle<ObjectTemplate> objTpl;
>
> Handle<Value> jsnative_print(const Arguments& args) {
> for (int i = 0; i < args.Length(); i++) {
> HandleScope handle_scope;
> if( i > 0 )
> cout << ' ';
> cout << *String::AsciiValue( args[i] );
> }
> cout << endl;
> return Undefined();
> }
>
> void RemoveMyObj( Persistent<Value> object, void *parameter ) {
> cout << "RemoveMyObj()\n";
> }
>
> /*
> // Alternative version of object constructor, which returns weak
> handle
> // to new obejct itself (try adding a slash above to check it out)
> Handle<Value> jsnative_myobj(const Arguments& args) {
> if( args.IsConstructCall() ) {
> Persistent<Object> obj( objTpl->NewInstance() );
> obj.MakeWeak( 0, RemoveMyObj );
> return obj;
> }
> else
> return Undefined();
> }
> /*/
> // Basic version of object constructor. Stores a weak handle
> // in an internal field of the object
> Handle<Value> jsnative_myobj(const Arguments& args) {
> if( args.IsConstructCall() ) {
> HandleScope handle_scope;
> Local<Object> obj = objTpl->NewInstance();
> Persistent< Number > hm = Persistent< Number>::New( Number::New( 1 )
> );
>
> hm.MakeWeak( 0, RemoveMyObj );
> obj->SetInternalField( 0, hm );
> return handle_scope.Close( obj ); // At this point, only obj
> local handle shoud survive
> }
> else
> return Undefined();
> }
> //*/
>
> int main( int argc, char **argv )
> {
> // Create a stack-allocated handle scope.
> HandleScope handle_scope;
>
> // Create a new context.
> const char* extension_list[] = { "v8/gc" };
> ExtensionConfiguration extensions(1, extension_list);
> Persistent<Context> context = Context::New(&extensions);
>
> // Enter the created context for compiling and
> // running the hello world script.
> Context::Scope context_scope(context);
>
> // Create object template
> objTpl = ObjectTemplate::New();
> objTpl->SetInternalFieldCount( 1 );
>
> // Add "print()" JS function
> Local<FunctionTemplate> f_print =
> FunctionTemplate::New(jsnative_print);
> context->Global()->Set( String::New("print"), f_print-
>
> >GetFunction() );
>
> // Add my object constructor
> Local<FunctionTemplate> f_myobj =
> FunctionTemplate::New(jsnative_myobj);
> f_myobj->SetClassName( String::New("MY_OBJ") );
> context->Global()->Set( String::New("myobj"), f_myobj-
>
> >GetFunction() );
>
> // Run the script and get the result.
> string scriptText =
> "for( i=1; i<1000000; ++i ) {\n"
> " o = new myobj\n"
> " if( i % 100 == 0 )\n"
> " { print( i ); gc(); }\n"
> " o.p1 = '123';\n"
> " o.p2 = i.toString();\n"
> " }\n";
> Handle<Value> result =
> Script::Compile( String::New( scriptText.c_str() ) )->Run();
> context.Dispose();
> cout << *String::AsciiValue(result) << endl;
> V8::Dispose();
> return 0;
> }
> ---- 8< ----
>
> > One thing that looks wrong, unrelated to your question, is that you're
> > creating a new object template in a local handle and then returning it.
> > Once that Local handle goes out of scope I believe your object is
> > considered garbage.
>
> I suppose that the main property of local handles is that their
> lifetime is determined by lifetime of the HandleScope instance on the
> stack, and by corresponding scope. In our case, we have such an object
> in main(); in last example, also in jsnative_myobj().
>
>
>
> > I think v8 has already created an object for you to store your result in
> > and put it in args.Holder(); What you should do is create a
> > FunctionTemplate and setup the functiontemplate->InstanceTemplate() like
> > your objTpl below (give it the appropriate field count, property
> > handlers, etc). Use the function template instance's ->GetFunction() for
> > the function used for construction. Then your callhandler should just
> > store the persistent pointer to the c++ object in args.Holder(), and
> > return that.
>
> Do you mean that object being created should be written to
> args.Holder()?
> Unfortunately v8::Arguments is undocumented...
>
> > As for why the garbage collector doesn't fire I have no idea. I am not
> > sure that it should be. Perhaps someone else could step in here?
>
> In new example, gc invocation is forced, and nothing still hapens.
> Please help me someone! :)
>
> Regards,
> Deadmorous
>
>
>
> > Best,
> > Alfred
>
> > On Sun, 2010-02-21 at 14:57 -0800, deadmorous wrote:
> > > Strange, the handler isn't called at all. Here is the code of
> > > constructor of example JS object:
> > > ---- 8< ----
> > > v8::Handle<v8::Value> jsnative_myobj(const v8::Arguments& args) {
> > > if( args.IsConstructCall() ) {
> > > // Create object template here (well, this is just a test,
> > > performance doesn't matter)
> > > Handle<ObjectTemplate> objTpl = ObjectTemplate::New();
> > > objTpl->SetInternalFieldCount( 1 );
> > > objTpl->SetNamedPropertyHandler(
> > > MyNamedPropertyGetter, MyNamedPropertySetter,
> > > MyNamedPropertyQuery, MyNamedPropertyDeleter,
> > > MyNamedPropertyEnumerator );
>
> > > // Create new object instance
> > > Local<v8::Object> obj = objTpl->NewInstance();
>
> > > // Store an application-specific pointer in an internal field
> > > as a persistent handle
> > > Persistent< External > hm( External::New( new
> > > map<string,string>() ) ); // Set handle data
> > > hm.MakeWeak( 0, RemoveMyObj ); // Make the handle weak,
> > > specify the callback
> > > obj->SetInternalField( 0, hm ); // Store handle in internal
> > > field
>
> > > // Return instance just created, which should cause the
> > > current This object to be discarded.
> > > return obj;
> > > }
> > > else
> > > return v8::Undefined();
> > > }
> > > ---- 8< ----
> > > The corresp. function object is created using a function template and
> > > set as a global property:
> > > ---- 8< ----
> > > Local<FunctionTemplate> f_myobj =
> > > FunctionTemplate::New(jsnative_myobj);
> > > f_myobj->SetClassName( String::New("MY_OBJ") );
> > > context->Global()->Set( String::New("myobj"), f_myobj-
> > > >GetFunction() );
> > > ---- 8< ----
> > > Then I execute the following script:
> > > ---- 8< ----
> > > for( i=1; i<1000000; ++i ) {
> > > o = new myobj
> > > if( i % 100 == 0 ) print( i );
> > > o.p1 = "123";
> > > o.p2 = i.toString();
> > > }
> > > ---- 8< ----
> > > I expect that GC would remove instances created in a loop, which
> > > causes weak handles in internal fields of my instances to die, which
> > > in turn causes the invocation of the RemoveMyObj() handle.
> > > Unfortunally, this doesn't happen; task manager shows that memory
> > > usage constantly grows. What am I doing wrong?
>
> > > Regards,
> > > Deadmorous
>
> > > On 22 фев, 00:54, deadmorous <[email protected]> wrote:
> > > > Yes, exactly; I have smart pointers with reference counting in my app,
> > > > but this doesn't matter.
>
> > > > Actually, as wou warned, my callback hasn't been called in a small
> > > > example, even though the engine should have shut down (I called
> > > > Persistent<Context>::Dispose() for the context, and V8::Dispose()
> > > > afterwards). Still my handler has not been called. Well, if this is
> > > > just becasue GC hasn't worked a single time, I can of course kill all
> > > > of my instances after engine shutdown. Will also try running a more
> > > > memory intensive test script to find out what's going on...
>
> > > > On 21 фев, 23:32, Alfred Rossi <[email protected]> wrote:
>
> > > > > You should hold your object in a weak persistent reference from the
> > > > > start.
>
> > > > > If I understand you correctly, I think what you actually want to do is
> > > > > create a Persistent::External for holding your wrapped class pointer,
> > > > > and call MakeWeak on that. The handler given to MakeWeak should cast
> > > > > the
> > > > > pointer back to it's original type and delete it. The rest about
> > > > > deleting after removal is automatic and happens as deemed necessary by
> > > > > the garbage collector.
>
> > > > > On Sun, 2010-02-21 at 12:28 -0800, deadmorous wrote:
> > > > > > Well, the most important to me is to take some action in responce to
> > > > > > adding/removing properties, which is done using interceptors. Once a
> > > > > > JS property is removed, I can reflect that in my own property tree,
> > > > > > and also call Persistent::MakeWeak() on the object referred to by
> > > > > > the
> > > > > > property that's being removed. Then at some time GC would remove JS
> > > > > > instance, which in turn would dereference my instance, which in turn
> > > > > > would typically remove it. At least this is how I see that now -
> > > > > > will
> > > > > > try to implement. V8's API is not obvious, though SpiderMonkey's is
> > > > > > harder to understand and use)
>
> > > > > > On 21 фев, 20:44, Alfred Rossi <[email protected]> wrote:
> > > > > > > I think global here is referring to the global HandleScope and
> > > > > > > not the
> > > > > > > owning object. I suspect that by holding it with a persistent
> > > > > > > handle
> > > > > > > you globalize (free it's ties to C++ scope dependent handles like
> > > > > > > Local) the object. According to the Embedder's Guide:
>
> > > > > > > "Persistent handles are not held on a stack and are deleted only
> > > > > > > when
> > > > > > > you specifically remove them. Just like a local handle, a
> > > > > > > persistent
> > > > > > > handle provides a reference to a heap-allocated object. Use a
> > > > > > > persistent handle when you need to keep a reference to an object
> > > > > > > for
>
> ...
>
> продолжение »
--
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users