# Array not released

This topic is 1244 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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;
}
}
Then I skip few frames and in 'b' I see always 2 (in debugger), not 1 as expected.
Please check this moment.

##### Share on other sites

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.

##### Share on other sites

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().

##### Share on other sites

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.

##### Share on other sites

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.

##### Share on other sites

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?

##### Share on other sites

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?

##### Share on other sites

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.

##### Share on other sites

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.

##### Share on other sites

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.

Edited by cvet

##### Share on other sites

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

This is true. In this situation the array will stay alive until you manually call the GC, hence the array will hold on to the reference to the mytype stored in it.

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).

Even a short can count up to 32767. If you have that many references to the same object, then you might want to rethink your design.

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.

Yes, it is normal for GC objects to hold non-GC objects. AngelScript has no way of knowing that mytype cannot be derived from and thus cannot form a circular reference.

I already have plans of adding an extra flag to allow the application to tell AngelScript that a registered type cannot under any circumstances form a circular reference. The CScriptArray and other classes will then not have to garbage collected just because they can contain a handle to this type.

##### Share on other sites

Even a short can count up to 32767. If you have that many references to the same object, then you might want to rethink your design.

Nothing to do with design.

If I switch off FPS limiter then my application get ~700 FPS, and it reach 32767 just for 46 seconds. As I say before myfunc invoked every frame.

For now I switch application to built-in automatic garbage collector, because our manual works not good as I see.