Advertisement

Array not released

Started by September 26, 2014 10:22 AM
10 comments, last by cvet 10 years, 1 month ago

AngelScript revision 1996.

Array (at least, not check other types) not released and as result I have leaked arrays and stored pointers in it.

Script
void main()
{
mytype@[] a;
myfunc(a);
}

Native
RegisterGlobalFunction( "void myfunc(mytype@[]@+ a)" )
ScriptArray* b = 0;
void myfunc(ScriptArray* a)
{
// 'a' have refCount == 3 at input, this is correct?
if (!b)
{
b = a;
b->AddRef();
}
}
Then I skip few frames and in 'b' I see always 2 (in debugger), not 1 as expected.
Please check this moment.

If 'myType' needs to be garbage collected, or might need to be garbage collected (not sure of the exact logic for arrays), the array will also be garbage collected. The GC will hold a reference to whatever was added to it until the GC decides it can be deleted.

Advertisement

ThyReaper has the right of it.

The VM notifies the GC about the array instance at creation (counts for 1 reference) since it can potentially be involved in a circular reference (e.g. array -> mytype -> array, or array -> type derived from mytype -> array).

This is why it has a refcount of 3 when you inspect the object at the entry of the myfunc() call. 1 is held by the garbage collector, 1 is held by the local variable in the script, and 1 is the reference being passed into the myfunc().

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Yes, this is true, I was forgot about GC.

Then there another bug - asBEHAVE_RELEASEREFS not invoked, because objects in array not released, also I set breakpoint in ReleaseAllHandles and debugger not stop on it.

The GC only calls ReleaseAllHandles() if it detects a circular reference, which is not the case here.

The GC will hold on to its reference of the object until all other references have been released. You're storing a reference in the variable ScriptArray *b and calling AddRef(). Until you call Release() to release that reference, the GC must not release its reference either.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

This is just example, here another to describe last bug

Script

void main()
{
mytype@[] a;
myfunc(a);
}

Native

mytype* b = new mytype();

void myfunc(ScriptArray* a)
{
a->Resize(1);

a->SetValue(0, (void*)&b);
}

Here ReleaseAllHandles must invoked or not?

Advertisement

In dovumentation I see this

...ReleaseAllReferences

// When we receive this call, we are as good as dead, but
// the garbage collector will still hold a references to us, so we
// cannot just delete ourself yet. Just free all references to other
// objects that we hold

By this description ReleaseAllReferences must call in my situation. Isn't it?

In any way, even ReleaseAllReferences not used for this, array object can contain objects not managed by GC and it prevent their releasing until GC not release array.

No, ReleaseAllReferences will not be called in this second example either. ReleaseAllReferences is only called if a circular reference is detected that has to be broken by the garbage collector in order to be able to release the objects.

You have this code in your second example:

mytype* b = new mytype();  // I assume this is a global variable. Where are you releasing the reference created by the constructor?
void myfunc(ScriptArray* a) // I assume you've registered the function as "void myfunc(array<mytype@>[]@+)" as in your first example
{
  a->Resize(1);
  a->SetValue(0, (void*)&b);  // This will increment the refcount to the mytype so that it is now 2
}

After the function call the array will go out of scope and will be released. As no other references to the array exists, the garbage collector will also release its reference, and thus the array will be destroyed which will in turn release the reference to mytype.

However, even after the array is destroyed, your application is still holding on to a reference to mytype which is why it is not destroyed.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

After the function call the array will go out of scope and will be released. As no other references to the array exists, the garbage collector will also release its reference, and thus the array will be destroyed which will in turn release the reference to mytype.

If I disable automatic garbage collection and will not call GC explicitly then array not will be released and all handles in it too.

However, even after the array is destroyed, your application is still holding on to a reference to mytype which is why it is not destroyed.

I do not say about destroying, I say about releasing. Because in mytype used 'short' for refCount and I have overflow after some time if GC not invoked (myfunc is called every frame).

If you say this is normal behaviour that GC objects can hold not GC objects before GC kill it, then it's ok, I just want point on this behaviour.

This topic is closed to new replies.

Advertisement