Advertisement

Garbage Collector Crashing

Started by May 25, 2011 12:23 AM
4 comments, last by WitchLord 13 years, 9 months ago
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: http://www.bulletphy...sbtVector3.html

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


#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



#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);


}

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

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

Advertisement

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.




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

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

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

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 topic is closed to new replies.

Advertisement