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
> > > > > > more than one function call, or when handle lifetimes do not
> > > > > > correspond to C++ scopes...."
>
> > > > > > "...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."
>
> > > > > > The comments and documentation leave me with the impression that
> > > > > > when
> > > > > > one object holds another it does not do so using a weak persistent
> > > > > > handle, and thus the garbage collector is prevented from invoking
> > > > > > the
> > > > > > callback.
>
> > > > > > This gets into internals which I am not too keen on (I am just a
> > > > > > user
> > > > > > like yourself), but there are developers on this list that can jump
> > > > > > in
> > > > > > should you like to know more.
>
> > > > > > Best,
> > > > > > Alfred
>
> > > > > > On Sun, Feb 21, 2010 at 12:17 PM, deadmorous <[email protected]>
> > > > > > wrote:
> > > > > > > Thank you very much, Alfred.
> > > > > > > This seems to be exactly what I asked for. :) One thing I still
> > > > > > > don't
> > > > > > > understand is the description of "object" parameter in
> > > > > > > WeakReferenceCallback, saying "the weak global object to be
> > > > > > > reclaimed
> > > > > > > by the garbage collector". Why "global"? What if the object was a
> > > > > > > property of some other object, and the property was then removed?
>
> > > > > > > Best regards,
> > > > > > > Deadmorous
>
> > > > > > > On 21 фев, 19:32, Alfred Rossi <[email protected]> wrote:
> > > > > > >> I apologize, that was supposed to say "The garbage collector is
> > > > > > >> NOT
> > > > > > >> guaranteed..."
>
> > > > > > >> Best,
> > > > > > >> Alfred
>
> > > > > > >> On Sun, 2010-02-21 at 11:31 -0500, Alfred Rossi wrote:
> > > > > > >> > You're looking for Persistent::MakeWeak. You can use MakeWeak
> > > > > > >> > to specify
> > > > > > >> > a callback to be invoked when the object is about to be garbage
> > > > > > >> > collected.
>
> > > > > > >> > You should be careful about building in an alternate way to
> > > > > > >> > free your C
> > > > > > >> > ++ objects. The garbage collector is guaranteed to be run,
> > > > > > >> > ever, even
> > > > > > >> > after the context has been disposed.
>
> > > > > > >> > See this for more details:
> > > > > > >> >http://stackoverflow.com/questions/173366/how-do-you-free-a-wrapped-c...
>
> > > > > > >> > Best,
> > > > > > >> > Alfred
>
> > > > > > >> > On Sun, 2010-02-21 at 08:24 -0800, deadmorous wrote:
> > > > > > >> > > Hello,
> > > > > > >> > > I'm trying to use V8 to expose functionality of my app to JS.
> > > > > > >> > > In my app, there are objects with properties and methods,
> > > > > > >> > > organized as
> > > > > > >> > > a tree of properties;
> > > > > > >> > > object instances can be created and added to the tree.
> > > > > > >> > > I understand how to expose my properties using V8
> > > > > > >> > > interceptors, and
> > > > > > >> > > think that it's correct to expose my
> > > > > > >> > > methods as properties of prototypes. Further, I would like
> > > > > > >> > > objects to
> > > > > > >> > > be creatable from JS code,
> > > > > > >> > > so I would expose my native constructors to JS. It happens
> > > > > > >> > > that I have
> > > > > > >> > > to have a duality between my instances
> > > > > > >> > > and JS instances. In my app, I would put a handle to JS
> > > > > > >> > > instance
> > > > > > >> > > corresponding to my instance;
> > > > > > >> > > and vice versa, I can put a pointer to my instance into
> > > > > > >> > > corresponding
> > > > > > >> > > JS instance, by using
> > > > > > >> > > Object::SetInternalField(), and using a value of type
> > > > > > >> > > External.
>
> > > > > > >> > > Now to my question. What I really don't understand - how can
> > > > > > >> > > I know
> > > > > > >> > > that a JS object is being destroyed?
> > > > > > >> > > I really need to know that, at least in order to destroy my
> > > > > > >> > > instance
> > > > > > >> > > attached to the one being destroyed in JS.
>
> > > > > > > --
> > > > > > > v8-users mailing list
> > > > > > > [email protected]
> > > > > > >http://groups.google.com/group/v8-users
--
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users