GameMonkey Script

GameMonkey Script Forums
It is currently Mon Nov 20, 2017 3:31 pm

All times are UTC




Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Sat Dec 29, 2012 9:55 pm 
Offline

Joined: Fri Jun 19, 2009 12:39 pm
Posts: 31
I have an issue where an object that is created in script code, is getting gc'd twice. Given my past experiences with GC, I'm 100% certain that it's my fault.

I think the cause of the problem is that I'm maintaining a list a std::map of the objects. My map stores gmVariable instances as the value type, which, when added create a gmUserObject via gmVariable::SetUser(). The reason that I do this, is so that when I maintain internal lists of objects, they update reference counts so that if the only reference of the objects is the list, the script object won't be destroyed.

The code to add objects to the map goes a little like this :-

Code:
void sGameObjectLinker::addObject(gmThread* a_thread, const char* pName, sGameObject* pObject)
{
   pObject->setNameNative(pName);
   pObject->setLinker(this);

   gmVariable var;
   var.SetUser(a_thread->GetMachine(), pObject, pObject->getType()->getId());
      
   mObjects[pObject->getNameCrc()] = var;
}


And in script code, I do the following :-

Code:
   global gObjectSim;
   gObjectSim = sGameObjectSim();
   myObject = sGameObject();
   gObjectSim.addObject("testobj", myObject);
   
   gObjectSim.removeObject(myObject);


What I end up with, is the sGameObject() being gc'd twice. Which makes sense, as I have two references; the local variable in script and the std::map in sGameObjectLinker. Am I supposed to generate a new gmUserObject any time I assign the item to a gmVariable, or is this object passed and there should only be one for every instance of my script exposed types?

Any idea where I'm going wrong?


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 29, 2012 10:53 pm 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 698
If your object's destructor (finalizer) code deletes the native object, you really only want one gmObject. So make lots of gmVariables, but only make one gmObject. The common way to do this is create the gmObject for the native instance once, or on demand once, and allow it to be retrieved whenever it's needed.

As for GC handling... If script stores an instance of the gmObject, native code need to nothing. However if script does not retain an instance, native code must manage the gmObject to prevent GC from occurring while the object is still alive. In your case, it appears the script type 'sGameObjectSim' is a container and exists in script, so it would likely need a destructor and write barrier.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 30, 2012 12:31 am 
Offline

Joined: Fri Jun 19, 2009 12:39 pm
Posts: 31
Thanks, Greg.

Greg wrote:
If your object's destructor (finalizer) code deletes the native object, you really only want one gmObject. So make lots of gmVariables, but only make one gmObject. The common way to do this is create the gmObject for the native instance once, or on demand once, and allow it to be retrieved whenever it's needed.


Understood. This is something I already have a machine allocated gmUserObject contained within the class instance, but when I return the object from it's script constructor, I create another and push it on to the thread stack.

So what I should be doing, is pushing the existing gmUserObject onto the stack.


Quote:
As for GC handling... If script stores an instance of the gmObject, native code need to nothing. However if script does not retain an instance, native code must manage the gmObject to prevent GC from occurring while the object is still alive. In your case, it appears the script type 'sGameObjectSim' is a container and exists in script, so it would likely need a destructor and write barrier.


The idea is that native code manages the object, with script code only storing references as needed (on creation, from searches etc). I already have the destructor for the object called from when GC happens, but I'm not too sure why I would need a write barrier as by this time.

By the time the object is GC'd, there shouldn't be anythign trying to access any members and changing/querying its state.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 30, 2012 12:56 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 698
BinaryDad wrote:
...So what I should be doing, is pushing the existing gmUserObject onto the stack.
That's right. PushUser() or use the gmVariable constructors or helpers that take a gmUserObject.
Quote:
The idea is that native code manages the object, with script code only storing references as needed (on creation, from searches etc). I already have the destructor for the object called from when GC happens, but I'm not too sure why I would need a write barrier as by this time.
Ok. Try stressing the code a bit and do things like call CollectGarbage() to make sure it works properly. Typically script containers need write barriers but your usage may not require it. Typically native code that 'owns' script objects need to use the gmGCRoot<> or *CPPOwnderGMObject() helpers to prevent premature GC when the object leaves script.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 30, 2012 1:34 am 
Offline

Joined: Fri Jun 19, 2009 12:39 pm
Posts: 31
Greg wrote:
Ok. Try stressing the code a bit and do things like call CollectGarbage() to make sure it works properly.


I'll give that a go once its working.


Quote:
Typically script containers need write barriers but your usage may not require it. Typically native code that 'owns' script objects need to use the gmGCRoot<> or *CPPOwnderGMObject() helpers to prevent premature GC when the object leaves script.


I had originally thought about just using the CPP owned object, but I can't remember right now why I thought this wasn't a great idea. It worked just fine, so I might revert back.

I think the problem is that I'mm over complicating things a little, and the more I think about it, my native side container doesn't really "own" the object at all. I just wanted to make sure that the object wasn't deleted once any script side variables released their reference to the object while it was still ref'd by the container.

Maybe just having a release() function that get's called from script is the best way to make sure the object is deleted when it needs to be, as by definition, its lifetime really is a "known thing".


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group