ref-counted object returned from C++ side not released

Started by
3 comments, last by jiandingzhe 2 years, 12 months ago

I made some short code to test it. This is the script part:

static const char* code =
    "void main() {\n"
    "    array<MyObj@>@ the_array = testfunc();\n"
    "    console_log( string(the_array.length()) );\n"
    "    for (int i =0; i < the_array.length(); i++) {\n"
    "        console_log( \"  \" + string(i) + \": refcount \" + string(the_array[i].getrefcount()) );\n"
    "    }\n"
    "}";

It obtains an array created from C++ side function testfunc, and print reference counts in its contents. After the script exit, the C++ destructor of MyObj class is not called, the array object is not released, and the memory pool reports several unreleased chunks.

The array type I used is the one shipped with AngelScript source package. And this is the related C++ code:

struct MyObj : public juce::ReferenceCountedObject
{
    MyObj() { juce::Logger::writeToLog( "MyObj " + juce::String::toHexString( size_t( this ) ) + " constructed" ); }
    virtual ~MyObj() { juce::Logger::writeToLog( "MyObj " + juce::String::toHexString( size_t( this ) ) + " destructed" ); }

    JUCE_LEAK_DETECTOR( MyObj );
};

void MyObj_ref( asIScriptGeneric* as )
{
    auto* self = (MyObj*) as->GetObject();
    self->incReferenceCount();
}

void MyObj_unref( asIScriptGeneric* as )
{
    auto* self = (MyObj*) as->GetObject();
    self->decReferenceCount();
}

void MyObj_getrefcount( asIScriptGeneric* as )
{
    auto* self = (MyObj*) as->GetObject();
    as->SetReturnDWord( self->getReferenceCount() );
}

static ashelper::CScriptArray* hackptr = nullptr;

void testfunc( asIScriptGeneric* as )
{
    auto* tinfo = as->GetEngine()->GetTypeInfoByDecl( "array<MyObj@>" );
    auto* re = ashelper::CScriptArray::Create( tinfo, 3 );
    hackptr = re;
    auto obj1 = new MyObj();
    re->SetValue( 0, &obj1 );
    auto obj2 = new MyObj();
    re->SetValue( 1, &obj2 );
    auto obj3 = new MyObj();
    re->SetValue( 2, &obj3 );
    as->SetReturnObject( re );
}

C++ type register part:

ashelper::registerRefObj( engine, "MyObj" );
    ashelper::registerObjBehavior( engine, "MyObj", asBEHAVE_ADDREF, "void f()", MyObj_ref );
    ashelper::registerObjBehavior( engine, "MyObj", asBEHAVE_RELEASE, "void f()", MyObj_unref );
    ashelper::registerObjMethod( engine, "MyObj", "int getrefcount() const", MyObj_getrefcount );

    ashelper::registerFunc( engine, "array<MyObj@>@ testfunc()", testfunc );

Script running part, the array object's holding status is printed in a hacky way:

// run script
    asIScriptContext* ctx = engine->CreateContext();
    auto* func = mod->GetFunctionByDecl( "void main()" );
    ctx->Prepare( func );
    if ( ctx->Execute() != 0 )
    {
        juce::Logger::writeToLog( juce::String( "exec failed: " ) + ctx->GetExceptionString() );
    }
    juce::Logger::writeToLog( "array object refcount after execution: " + juce::String( hackptr->GetRefCount() ) );

And console output:

MyObj 1f11cc5af50 constructed
MyObj 1f11cc5b310 constructed
MyObj 1f11cc5afb0 constructed
3
  0: refcount 1
  1: refcount 1
  2: refcount 1
array object refcount after execution: 1
WARNING at line 0, col 0: There is an external reference to an object in module 'TheModule', preventing it from being deleted
Advertisement

I noticed the warning after script execution. How should I declare the signature for testfunc()?

If I register as array<MyObj@>@+ testfunc(), it is even worse: the ref count to the array after script execution becomes 2.

The problem is not how you have registered the function. But the fact that you use gen->SetReturnObject(re) to return the handle. This call increases the reference counter on the script array, but you already have one reference counted with the creation of the array.

Either use the method SetReturnAddress() which doesn't increase the ref count, or call Release() on the script array after the call to SetReturnObject().

Regards,
Andreas

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

@WitchLord So I comprehend more on ref counting of this language, thanks for a lot!

This topic is closed to new replies.

Advertisement