Sign in to follow this  
_orm_

Garbage Collector Crashing

Recommended Posts

I remember this giving me trouble before, but calling any iteration of CollectGarbage is giving me problems. What's worse is that the stacktrace gdb gives me is completely useless. Seems like heap corruption to me. Recently I added some 3D math classes that inherit from bullets 3d math classes. It is possible I am doing it horribly wrong. It all compiles and runs fine up until i call Garbage Collect, and it doesn't matter what parameters I pass in. The docs to the btVector3 are here: [url="http://www.bulletphysics.com/Bullet/BulletFull/classbtVector3.html"]http://www.bulletphy...sbtVector3.html[/url]

Warning, lots of code ahead. I would post more, but I really have no more details to give.

[code]
#pragma once
#ifndef IRRE_BULLETSCRIPTMATH_H
#define IRRE_BULLETSCRIPTMATH_H

#include "../../shared/ScriptingInclude.h"

#include "../../deps/bullet/src/btBulletCollisionCommon.h"
#include "../../deps/bullet/src/btBulletDynamicsCommon.h"
#include <iostream>

namespace Irre {

class Vector3 : public btVector3
{
public:
Vector3():btVector3(){m_RefCount = 1;}
Vector3(float x,float y,float z):btVector3(x,y,z){m_RefCount = 1;}
Vector3(const btVector3& v):btVector3(v){m_RefCount=1;}

int operator==(const Vector3& v) const
{
return (int)btVector3::operator==(v);
}

int operator!=(const Vector3& v) const
{
return (int)btVector3::operator!=(v);
}

Vector3& Neg()
{
*this = *this * -1;
return *this;
}

Vector3& MulAssign(const float& in)
{
//this->btVector3::operator*=(in);
*this = *this * in;
return *this;
}

Vector3& MulAssign2(const Vector3& in)
{
*this = *this * in;
return *this;
}

Vector3* Add(const Vector3& in)
{
return new Vector3(*this + in);
}
/*Vector3* Add2(const float& in)
{
return new Vector3(*this + in);
}*/
Vector3* Sub(const Vector3& in)
{
return new Vector3(*this - in);
}
/*Vector3* Sub2(const float& in)
{
return new Vector3(
*this.x - in
);
}*/

Vector3* Div(const Vector3& in)
{
return new Vector3(*this / in);
}
Vector3* Div2(const float& in)
{
return new Vector3(*this / in);
}

Vector3* Mul(const Vector3& in)
{
return new Vector3(*this * in);
}

Vector3* Mul2(const float& in)
{
return new Vector3(*this * in);
}

void AddRef(){m_RefCount++;}
void Release(){if(--m_RefCount==0)delete this;}

private:
int m_RefCount;
};

class Rotation : public btQuaternion
{
public:
Rotation(){}

void AddRef(){m_RefCount++;}
void Release(){if(--m_RefCount==0)delete this;}

private:
int m_RefCount;
};


class Transform : public btTransform
{
public:
Transform(){m_RefCount=1;}
Transform(const btTransform& t):btTransform(t){m_RefCount=1;}


Vector3* GetBasis0()
{
return new Vector3(getBasis()[0]);
}
Vector3* GetBasis1()
{
return new Vector3(getBasis()[1]);
}
Vector3* GetBasis2()
{
return new Vector3(getBasis()[2]);
}

Vector3* GetOrigin()
{
return new Vector3(getOrigin());
}

void AddRef(){m_RefCount++;}
void Release(){if(--m_RefCount==0)delete this;}

private:
int m_RefCount;
};



void RegisterBulletScriptMath(asIScriptEngine* e);

}


#endif[/code]

[code]
#include "BulletScriptMath.h"
#include "../../shared/Global.h"

#include <iostream>

namespace Irre {

Vector3* VectorFactory()
{
return new Vector3();
}

Vector3* VectorFactory2(float x,float y,float z)
{
return new Vector3(x,y,z);
}

Transform* TransformFactory()
{
return new Transform();
}

Transform* TransformFactory2(const Rotation* r,const Vector3* v)
{
}

Rotation* RotationFactory()
{
return new Rotation();
}


void RegisterBulletScriptMath(asIScriptEngine* e)
{
int r=0;
r=e->RegisterObjectType("Vector",0,asOBJ_REF);AS_CHECK(r);
r=e->RegisterObjectType("Transform",0,asOBJ_REF);AS_CHECK(r);
// r=e->RegisterObjectType("Rotation",0,asOBJ_REF);AS_CHECK(r);

r=e->RegisterObjectBehaviour("Vector", asBEHAVE_FACTORY,"Vector@ f()", asFUNCTION(VectorFactory), asCALL_CDECL); AS_CHECK(r);
r=e->RegisterObjectBehaviour("Vector", asBEHAVE_FACTORY,"Vector@ f(float,float,float)", asFUNCTION(VectorFactory2), asCALL_CDECL); AS_CHECK(r);
r=e->RegisterObjectBehaviour("Vector", asBEHAVE_ADDREF,"void f()", asMETHOD(Vector3,AddRef), asCALL_THISCALL); AS_CHECK(r);
r=e->RegisterObjectBehaviour("Vector", asBEHAVE_RELEASE,"void f()", asMETHOD(Vector3,Release), asCALL_THISCALL); AS_CHECK(r);

r=e->RegisterObjectBehaviour("Transform", asBEHAVE_FACTORY,"Transform@ f()", asFUNCTION(TransformFactory), asCALL_CDECL); AS_CHECK(r);
r=e->RegisterObjectBehaviour("Transform", asBEHAVE_FACTORY,"Transform@ f(const Rotation@,const Vector@)", asFUNCTION(VectorFactory2), asCALL_CDECL); AS_CHECK(r);
r=e->RegisterObjectBehaviour("Transform", asBEHAVE_ADDREF,"void f()", asMETHOD(Transform,AddRef), asCALL_THISCALL); AS_CHECK(r);
r=e->RegisterObjectBehaviour("Transform", asBEHAVE_RELEASE,"void f()", asMETHOD(Transform,Release), asCALL_THISCALL); AS_CHECK(r);

r=e->RegisterObjectMethod("Vector","Vector& opAddAssign(const Vector&in)", asMETHOD(Vector3,operator+=),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector& opSubAssign(const Vector&in)", asMETHOD(Vector3,operator-=),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod( "Vector","Vector& opMulAssign(const float&in)",asMETHOD(Vector3,MulAssign),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod( "Vector","Vector& opMulAssign(const Vector&in)",asMETHOD(Vector3,MulAssign2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector& opDivAssign(const float&in)",asMETHOD(Vector3,operator/=),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector& opNeg()", asMETHOD(Vector3,Neg),asCALL_THISCALL);AS_CHECK(r);

r=e->RegisterObjectMethod("Vector","Vector@ opAdd(const Vector&in)", asMETHOD(Vector3,Add),asCALL_THISCALL);AS_CHECK(r);
//r=e->RegisterObjectMethod("Vector","Vector@ opAdd(const float&in)", asMETHOD(Vector3,Add2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ opMul(const Vector&in)", asMETHOD(Vector3,Mul),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ opMul(const float&in)", asMETHOD(Vector3,Mul2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ opDiv(const Vector&in)", asMETHOD(Vector3,Div),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ opDiv(const float&in)", asMETHOD(Vector3,Div2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ opSub(const Vector&in)", asMETHOD(Vector3,Sub),asCALL_THISCALL);AS_CHECK(r);
//r=e->RegisterObjectMethod("Vector","Vector@ opSub(const float&in)", asMETHOD(Vector3,Sub2),asCALL_THISCALL);AS_CHECK(r);

r=e->RegisterObjectMethod("Vector","float dot(const Vector&in) const",asMETHOD(Vector3,operator/=),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","float Length2() const", asMETHOD(Vector3,length2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","float Length() const", asMETHOD(Vector3,length),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","float Distance2(const Vector&in) const", asMETHOD(Vector3,distance2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","float Distance(const Vector&in) const", asMETHOD(Vector3,distance),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector& Normalize()", asMETHOD(Vector3,normalize),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ Normalized() const", asMETHOD(Vector3,normalized),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ Rotate(const Vector&in,const float) const", asMETHOD(Vector3,rotate),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","float Angle(const Vector&in) const", asMETHOD(Vector3,angle),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ Absolute() const", asMETHOD(Vector3,absolute),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","Vector@ Cross(const Vector&in) const", asMETHOD(Vector3,cross),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","float Triple(const Vector&in,const Vector&in) const", asMETHOD(Vector3,triple),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","void SetInterpolate3(const Vector&in,const Vector&in,float)", asMETHOD(Vector3,setInterpolate3),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","void Lerp(const Vector&in,const float&in) const", asMETHOD(Vector3,lerp),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","const float& get_X() const", asMETHOD(Vector3,getX),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","const float& get_Y() const", asMETHOD(Vector3,getY),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","const float& get_Z() const", asMETHOD(Vector3,getZ),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","void set_X(float)", asMETHOD(Vector3,setX),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","void set_Y(float)", asMETHOD(Vector3,setY),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","void set_Z(float)", asMETHOD(Vector3,setZ),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","void set_W(float)", asMETHOD(Vector3,setW),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","int opEquals(const Vector&in) const", asMETHOD(Vector3,operator==),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Vector","int opEquals(const Vector&in) const", asMETHOD(Vector3,operator!=),asCALL_THISCALL);AS_CHECK(r);

r=e->RegisterObjectMethod("Transform","Transform& opAssign(const Transform&in)",asMETHOD(Transform,operator=),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Transform","Vector@ GetBasis0()", asMETHOD(Transform,GetBasis0),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Transform","Vector@ GetBasis1()", asMETHOD(Transform,GetBasis1),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Transform","Vector@ GetBasis2()", asMETHOD(Transform,GetBasis2),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Transform","void Mult(const Transform&in,const Transform&in)", asMETHOD(Transform,mult),asCALL_THISCALL);AS_CHECK(r);
r=e->RegisterObjectMethod("Transform","Vector@ GetOrigin() const", asMETHOD(Transform,GetOrigin),asCALL_THISCALL);AS_CHECK(r);
//r=e->RegisterObjectMethod("Transform","Rotation@ GetRotation(const Vector&in)", asMETHOD(Transform,GetRotation),asCALL_THISCALL);AS_CHECK(r);


}

}[/code]

Share this post


Link to post
Share on other sites
While I don't see anything directly wrong with what you're doing, you need to be very careful with any functions, methods, or properties that you register to make sure AngelScript doesn't accidentally call AddRef, Release on a Vector3 that is really a btVector3. If that happens you get memory corruption, which is quite possibly the cause of the crash you're experiencing in CollectGarbage.

Does the crash happen even without calling any scripts? If not, can you narrow down the size of the script that reproduces the crash?



Unrelated to your actual problem:

I don't think you should be registering the Vector3 as a reference type. This would probably be better suited as a value type.

Share this post


Link to post
Share on other sites
[quote name='WitchLord' timestamp='1306288911' post='4815400']
While I don't see anything directly wrong with what you're doing, you need to be very careful with any functions, methods, or properties that you register to make sure AngelScript doesn't accidentally call AddRef, Release on a Vector3 that is really a btVector3. If that happens you get memory corruption, which is quite possibly the cause of the crash you're experiencing in CollectGarbage.

Does the crash happen even without calling any scripts? If not, can you narrow down the size of the script that reproduces the crash?



Unrelated to your actual problem:

I don't think you should be registering the Vector3 as a reference type. This would probably be better suited as a value type.
[/quote]


Ironically, what you thought was unrelated was actually the root of the problem. After converting my Vector3 class to use the btVector3 as a core instead of inheriting from it, nothing was really fixed. But after converting it to a value type (and refactoring a metric ass-ton of scripts that treated the Vector as a reference), the garbage collector ran just fine.


I still personally believe that putting scripted objects on the stack is a bad idea. But if it works, I guess I can't really complain. What advantages do value types really hold over reference types?

Share this post


Link to post
Share on other sites
Think of value types as primitives, i.e. smaller types that are used for holding basic values. Value types have less overhead as they can for the most part be allocated on the stack, rather than in dynamic memory.

Share this post


Link to post
Share on other sites
Ah, so the Vector3 object is on the stack, but I'm guessing that Angelscript's stuff that is tracking it is in dynamic memory? (I seriously need to take a look at the guts of this beast.)

Share this post


Link to post
Share on other sites
Well, I haven't finished the optimizations in this regard, so there are still many situations where the value types are allocated on the heap, e.g. when a function returns a value type, or when a script class has a value type as a member. But this is transparent to the application, and I will eventually have it all moved to be allocated on the stack (or within the object memory for script classes).

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this