Speicherleaks



  • Hi 🙂

    ich lasse mir durch _CrtDumpMemoryLeaks(); meine Leaks anzeigen.
    Seit ich mein ganzes programm Objektorientiert gemacht habe sind einige sehr große Leaks enstanden.

    und ich frage mich was z.b. Uhrsachen dafür sein könnten.
    Z.B. ist folgender Destructor richtig?

    Hexapod :: Hexapod(D3DXVECTOR3* CamPos)
    {
    	m_CamPos	= CamPos;
    
    	unsigned int i;
    	for(i = 0; i < 6; i++)
    	{
    		m_bein[i] = new leg(m_CamPos, 0.0f, 0.0f, 0.0f, 0.0f);
    	}
    }
    
    Hexapod :: ~Hexapod()
    {
    	unsigned int i;
    	for(i = 0; i < 6; i++)	delete m_bein[i];
    }
    

    Ich vermute dort ist ein Fehler. Die Klasse Leg hat viele Daten, vorallem Matrizen. ich denke Hier ist sicherlich ein Leek, denn im Dump stehen 6 große leeks der selben größe:

    Dumping objects ->
    {184} normal block at 0x00AB8BB8, 104 bytes long.
     Data: <    h^   \   ]  > 1C F7 1C 00 68 5E AB 00 D0 5C AB 00 10 5D AB 00 
    {183} normal block at 0x00AB8B20, 92 bytes long.
     Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
    {182} normal block at 0x00AB8678, 1132 bytes long.
     Data: <                > 20 8B AB 00 00 00 00 00 00 00 00 00 00 00 00 00 
    {181} normal block at 0x00AB85E0, 92 bytes long.
     Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
    {180} normal block at 0x00AB8138, 1132 bytes long.
     Data: <                > E0 85 AB 00 00 00 00 00 00 00 00 00 00 00 00 00 
    {179} normal block at 0x00AB80A0, 92 bytes long.
     Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
    {178} normal block at 0x00AB7BF8, 1132 bytes long.
     Data: <                > A0 80 AB 00 00 00 00 00 00 00 00 00 00 00 00 00 
    {177} normal block at 0x00AB7B60, 92 bytes long.
     Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
    {176} normal block at 0x00AB76B8, 1132 bytes long.
     Data: <`{              > 60 7B AB 00 00 00 00 00 00 00 00 00 00 00 00 00 
    {175} normal block at 0x00AB7620, 92 bytes long.
     Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
    {174} normal block at 0x00AB7178, 1132 bytes long.
     Data: < v              > 20 76 AB 00 00 00 00 00 00 00 00 00 00 00 00 00 
    {173} normal block at 0x00AB70E0, 92 bytes long.
     Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD 
    {172} normal block at 0x00AB6C38, 1132 bytes long.
     Data: < p              > E0 70 AB 00 00 00 00 00 00 00 00 00 00 00 00 00 
    {141} normal block at 0x00AB5CC0, 440 bytes long.
     Data: <          HB  I@> 00 00 00 00 00 00 00 00 00 00 48 42 D8 0F 49 40 
    Object dump complete.
    

    wenn ich delete[] m_leg; mache kriege ich einen Laufzeitfehler beim schließen des Programms.



  • Der Array m_bein wird automatisch gelöscht im Destructor, also benutz doch einfach unique_ptr und du hast keine Probleme mehr mit memoryleeks 🙂



  • unique ptr höre ich grade zum ersten mal 😞
    ok ich hab jetzt ein bisschen dazu gelesen.
    aber in meinem konkreten beispiel sollte das doch trozdem funktionieren oder?



  • cl90 schrieb:

    Seit ich mein ganzes programm Objektorientiert gemacht habe sind einige sehr große Leeks enstanden.

    OOP != new/delete. Die sind bei dir ohnehin unnötig. Warum hast du ein Array von Zeigern und kein normales Array?

    OOP in C++ heisst RAII. Wenn du alles mit RAII machst und alle Zeiger als unique_ptr hältst, können prinzipiell keine Speicherlecks entstehen.



  • cl90 schrieb:

    aber in meinem konkreten beispiel sollte das doch trozdem funktionieren oder?

    Das sieht korrekt aus. Da du aber nur Schnipsel zeigst, kann da trotzdem noch etwas falsch sein ( z.B. Leg ist abgeleitet und die Basisklasse hat keinen virtuellen destruktor, das array enthält aber Zeiger auf die Basis)



  • Der gepostete Code ist ok. Benutzt du noch an anderen Stellen new/delete?



  • ja ich nutze hier und da weitere delete/new.
    Aber ich will hier nicht umbedingt alles mit 1-2 tausend zeilen code vollschreiben 😞
    ich konzentriere mich mal auf Leg und Hexapod.
    Ich vermute hier ja immernoch den größten fehler wegen der Dumps.

    Hexapod .h und .cpp

    #ifndef HEXAPOD_H_CL90
    #define HEXAPOD_H_CL90
    
    #include "init_configuration.h"
    #include "leg.h"
    
    class Hexapod
    {
    	public:
    		Hexapod(D3DXVECTOR3* CamPos);
    		~Hexapod();
    
    		leg*				get_leg(int number);
    
    	private:
    
    		leg*				m_bein[6];
    
    		D3DXVECTOR3*		m_CamPos;
    };
    
    #endif
    
    #include "hexapod.h"
    
    Hexapod :: Hexapod(D3DXVECTOR3* CamPos)
    {
    	m_CamPos	= CamPos;
    
    	unsigned int i;
    	for(i = 0; i < 6; i++)
    	{
    		m_bein[i] = new leg(m_CamPos, 0.0f, 0.0f, 0.0f, 0.0f);
    	}
    }
    
    Hexapod :: ~Hexapod()
    {
    	unsigned int i;
    	for(i = 0; i < 6; i++)	delete m_bein[i];
    }
    leg*				Hexapod :: get_leg(int number)
    {
    	if(number >= 0 && number < 6)
    	{
    		return m_bein[number];
    	}
    	return m_bein[0];
    }
    

    Leg .h und .cpp

    #ifndef LEG_H_CL90
    #define LEG_H_CL90
    
    #include "init_configuration.h"
    #include "iKin_math.h"
    
    class leg
    {
    	public:
    		leg(D3DXVECTOR3* CamPos, float x, float y, float z,  float degAngel);
    		~leg();
    
    		void				set_Target	(float x, float y, float z);
    		D3DXVECTOR3			get_Target	();
    		iKin_math*			get_iKin	();
    		void				set_angle	(int servo, float angle);
    		void				set_angle	(float an1, float an2, float an3, float an4);
    		float				get_angle	(int servo);
    		float				get_length	(int part);
    		D3DXVECTOR3			get_posVec	(int counter);
    
    		D3DXMATRIX			get_matTransform(int number);
    		D3DXMATRIX*			get_matSizePtr();
    		D3DXMATRIX*			get_matAxisSizePtr();
    		D3DXMATRIX*			get_mat90Ptr();
    
    	private:
    
    		iKin_math*			m_iKin;
    
    		void				m_refresh_transform();
    		float				m_angle[4];
    		D3DXMATRIX			m_matTransform[6];
    		D3DXVECTOR3			m_Origin;
    		D3DXVECTOR3			m_posVec[5];
    		D3DXVECTOR3			m_Target;
    
    		static	float		m_length[4];
    		static	float		m_PI;
    
    		D3DXMATRIX			m_matRot90;
    		D3DXMATRIX			m_matTurn;
    		D3DXMATRIX			m_matDir;
    		D3DXMATRIX			m_matSize;
    		D3DXMATRIX			m_matAxisSize;
    		D3DXMATRIX			m_matTransPos;
    		D3DXMATRIX			m_matTransSO;
    		D3DXMATRIX			m_matTransVS;
    		D3DXMATRIX			m_matTransOS;
    		D3DXMATRIX			m_matTransUS;
    
    		D3DXVECTOR3*		m_CamPos;
    };
    
    #endif
    
    #include "leg.h"
    
    float leg::m_PI			= 3.141592f;
    float leg::m_length[4]	= {3.29f,	1.5f,	6.78f, 8.07f};
    
    leg :: leg(D3DXVECTOR3* CamPos, float x, float y, float z,  float degAngel)
    {
    	m_Origin	= D3DXVECTOR3(x, y, z);
    
    	D3DXMatrixScaling		(&m_matSize,	     0.1f, 0.1f, 0.1f);
    	D3DXMatrixScaling		(&m_matAxisSize,   0.05f, 2.0f, 0.05f);
    	D3DXMatrixRotationZ		(&m_matRot90,		D3DXToRadian(-90));
    	D3DXMatrixRotationY		(&m_matTurn,		D3DXToRadian(180));
    	D3DXMatrixRotationY		(&m_matDir,	   D3DXToRadian(degAngel));
    	D3DXMatrixTranslation	(&m_matTransPos,			  x, y, z);
    	D3DXMatrixTranslation	(&m_matTransSO,    -m_length[0], 0, 0);
    	D3DXMatrixTranslation	(&m_matTransVS,		0, m_length[1], 0);
    	D3DXMatrixTranslation	(&m_matTransOS,		0, m_length[2], 0);
    	D3DXMatrixTranslation	(&m_matTransUS,		0, m_length[3], 0);
    
    	m_CamPos	= CamPos;
    
    	m_iKin		= new iKin_math(&m_Origin, &m_Target);
    
    	set_angle	(0.0f, 0.0f, 0.0f, 0.0f);
    
    	m_Target	= D3DXVECTOR3(10.0f, 0.0f, 0.0f);
    }
    
    leg ::~leg()
    {
    	delete m_iKin;
    }
    void leg :: set_Target	(float x, float y, float z)
    {
    	m_Target = D3DXVECTOR3(x, y, z);
    	//m_iKin->calc_Ang();
    	m_iKin->calc_Ang2();
    	set_angle(m_iKin->get_Angle(0), m_iKin->get_Angle(1), m_iKin->get_Angle(2), m_iKin->get_Angle(3));
    }
    D3DXVECTOR3 leg :: get_Target()
    {
    	return m_Target;
    }
    iKin_math*	leg :: get_iKin()
    {
    	return m_iKin;
    }
    void leg ::	set_angle(int servo, float angle)
    {
    	if(servo >= 0 && servo < 4)
    	{
    		m_angle[servo] = angle;
    	}
    	m_refresh_transform();
    }
    void leg :: set_angle(float an1, float an2, float an3, float an4)
    {
    	m_angle[0] = an1;
    	m_angle[1] = an2;
    	m_angle[2] = an3;
    	m_angle[3] = an4;
    	m_refresh_transform();
    }
    float leg :: get_angle(int servo)
    {
    	if(servo >= 0 && servo < 4)
    	{
    		return m_angle[servo];
    	}
    	return 0;
    }
    float leg :: get_length(int part)
    {
    	if(part >= 0 && part < 4)
    	{
    		return m_length[part];
    	}
    	return -1.0f;
    }
    D3DXVECTOR3 leg :: get_posVec(int counter)
    {
    	if(counter >= 0 && counter < 5)
    	{
    		return m_posVec[counter];
    	}
    	return D3DXVECTOR3(0.0f, 0.0f, 0.0f);
    }
    D3DXMATRIX leg :: get_matTransform(int number)
    {
    	if(number >= 0 && number < 6)
    	{
    		return m_matTransform[number];
    	}
    	return m_matTransform[0];
    }
    D3DXMATRIX* leg :: get_matSizePtr()
    {
    	return &m_matSize;
    }
    D3DXMATRIX* leg :: get_matAxisSizePtr()
    {
    	return &m_matAxisSize;
    }
    D3DXMATRIX* leg :: get_mat90Ptr()
    {
    	return &m_matRot90;
    }
    void leg :: m_refresh_transform()
    {
    	D3DXMATRIX	matRotAngle1;
    	D3DXMATRIX	matRotAngle2;
    	D3DXMATRIX	matRotAngle3;
    	D3DXMATRIX	matRotAngle4;
    
    	D3DXMatrixRotationX(&matRotAngle1,	m_angle[0]);
    	D3DXMatrixRotationY(&matRotAngle2, -m_angle[1]);
    	D3DXMatrixRotationZ(&matRotAngle3, -m_angle[2]);
    	D3DXMatrixRotationZ(&matRotAngle4,	m_PI-m_angle[3]);
    
    	m_matTransform[0]	= m_matTurn * m_matRot90 * m_matTransSO * m_matDir * m_matTransPos;
    	m_posVec[0]			= D3DXVECTOR3(m_matTransform[0]._41, m_matTransform[0]._42, m_matTransform[0]._43);
    
    	m_matTransform[1]	= m_matTurn * m_matRot90 * matRotAngle1* m_matDir  * m_matTransPos;
    	m_posVec[1]			= D3DXVECTOR3(m_matTransform[1]._41, m_matTransform[1]._42, m_matTransform[1]._43);
    
    	m_matTransform[2]	= m_matTurn * m_matRot90 * matRotAngle2 * matRotAngle1 * m_matDir * m_matTransPos;
    
    	m_matTransform[3]	= matRotAngle3 * m_matTransVS * m_matTurn * m_matRot90 * matRotAngle2 * matRotAngle1* m_matDir * m_matTransPos;
    	m_posVec[2]			= D3DXVECTOR3(m_matTransform[3]._41, m_matTransform[3]._42, m_matTransform[3]._43);
    
    	m_matTransform[4]	= matRotAngle4 * m_matTransOS * matRotAngle3 * m_matTransVS * m_matTurn * m_matRot90 * matRotAngle2 * matRotAngle1 * m_matDir * m_matTransPos;
    	m_posVec[3]			= D3DXVECTOR3(m_matTransform[4]._41, m_matTransform[4]._42, m_matTransform[4]._43);
    
    	m_matTransform[5]	= m_matTransUS * matRotAngle4 * m_matTransOS * matRotAngle3 * m_matTransVS * m_matTurn * m_matRot90 * matRotAngle2 * matRotAngle1 * m_matDir * m_matTransPos;
    	m_posVec[4]		= D3DXVECTOR3(m_matTransform[5]._41, m_matTransform[5]._42, m_matTransform[5]._43);
    }
    


  • Ich wiederhohle: Warum

    leg* m_bein[6];
    

    und nicht

    leg m_bein[6];
    

    ?



  • Warum hälst du soviele Daten als Zeiger und nicht als normale Variable zB:

    leg*                m_bein[6];
    D3DXVECTOR3*        m_CamPos;
    

    Das gleiche für die Rückgabetypen deiner Funktionen.

    Es sieht ein bischen danach aus als würdest du dir nicht ganz einig sein wer wann welche Besitzrechte übernimmt und damit verantwortlich für die zerstörung der Speicherbereiche ist.



  • Was ist mit campos?



  • gedächtnislücke schrieb:

    ... und alle Zeiger als unique_ptr hältst, können prinzipiell keine Speicherlecks entstehen.

    doch, ist bei mir jedenfalls noch so -.-
    aber die bibliothek die ich nutze fummelt sehr viel mit rohenzeigern rum



  • erstmal danke für die vielen Antworten 🙂

    gedächtnislücke schrieb:

    Ich wiederhohle: Warum

    leg* m_bein[6];
    

    und nicht

    leg m_bein[6];
    

    ?

    Wie soll ich leg m_bein inizialisieren? Wie rufe ich dann im Konstruktor von Hexapod den Konstruktor von leg auf?

    Xebov schrieb:

    Warum hälst du soviele Daten als Zeiger und nicht als normale Variable zB:

    leg*                m_bein[6];
    D3DXVECTOR3*        m_CamPos;
    

    naja weil dies Daten sind die diesem Objekt nicht gehören, sie aber darauf zugreifen müssen. m_CamPos ist ein D3DXVECTOR3 eines anderen Objekts, der aber von Leg benötigt wird. und damit leg immer den aktuellen vektor hat bekommt leg eben einen Pointer zum Originalvektor. Alternativ müsste Leg einen Pointer zum Objekt View_Light bekommen um mit get sich den vektor immer zu holen. die Variante find ich aber doof weil ich zu viele Kreisschlüsse bekomme was Pointertausch meiner Objekte angeht...

    manni66 schrieb:

    Was ist mit campos?

    Wie gesagt CamPos ist ein Pointer auf die Richtige CamPos. Wird auch im Konstruktor übergeben.



  • Ich sehe keinen operator=() oder Kopier-K'tor.
    Erfahrungsgemäß brauchst Du die aber, wenn Du mit Pointern hantierst...("Rule of three")



  • Furble Wurble schrieb:

    Erfahrungsgemäß brauchst Du die aber, wenn Du mit Pointern hantierst...("Rule of three")

    jein. Das gilt nur dann, wenn man Pointer selbst erzeugt. Teilweise scheinen hier Pointer auf extern erstellte Objekte gehalten zu werden. Bei diesen Pointern reicht es, die Adresse zu kopieren.

    Da aber m_bein im Objekt erzeugt wird, sind die erwähnten Methoden notwendig.



  • daddy_felix schrieb:

    Furble Wurble schrieb:

    Erfahrungsgemäß brauchst Du die aber, wenn Du mit Pointern hantierst...("Rule of three")

    jein. Das gilt nur dann, wenn man Pointer selbst erzeugt.

    Nicht einmal unbedingt dann. Wenn man intelligente Smart-Pointer mit Kopiersemantik hat, kann man sich auch die Big Three sparen...



  • ok ich ich glaube ich hab verstanden was ihr damit meint, bzw wo das Problem liegt.
    Aber ich weiß noch nicht so recht ob ich das jetzt richtig gemacht habe. für Hexapod hab ich jetzt keinen CopyK. und keinen Operator hinzugefügt da Hexapod einzigartig bleibt. Für aber Leg schon.
    Ich stell mich grade nur etwas an, und weiß nicht wie ich den Copyoperator jetzt richtig nutze, um m_bein in Hexapod richtig zu erstellen.
    Ich habs jetzt ohne pointer versucht, aber jetzt bekomm ich folgende meldung im Konstruktor von Hexapod:

    für die Klasse "leg" ist kein standard Konstruktor vorhanden
    

    Hexapod .h und .cpp

    #ifndef HEXAPOD_H_CL90
    #define HEXAPOD_H_CL90
    
    #include "init_configuration.h"
    #include "leg.h"
    
    class Hexapod
    {
    	public:
    		Hexapod(D3DXVECTOR3* CamPos);
    		~Hexapod();
    
    		leg*				get_leg(int number);
    
    	private:
    
    		leg				m_bein[6];
    
    		D3DXVECTOR3*		m_CamPos;
    };
    
    #endif
    
    #include "hexapod.h"
    
    Hexapod :: Hexapod(D3DXVECTOR3* CamPos)
    {
    	m_CamPos	= CamPos;
    
    	unsigned int i;
    	for(i = 0; i < 6; i++)
    	{
    		//m_bein[i] = new leg(m_CamPos, 0.0f, 0.0f, 0.0f, 0.0f);
    		m_bein[i] = leg(m_CamPos, 0.0f, 0.0f, 0.0f, 0.0f);
    	}
    }
    Hexapod :: ~Hexapod()
    {
    	unsigned int i;
    	//for(i = 0; i < 6; i++)	delete m_bein[i];
    	delete[] m_bein;
    }
    

    Änderungen in Leg .h .cpp

    #ifndef LEG_H_CL90
    #define LEG_H_CL90
    
    #include "init_configuration.h"
    #include "iKin_math.h"
    
    class leg
    {
    	public:
    		leg(D3DXVECTOR3* CamPos, float x, float y, float z,  float degAngel);
    		leg(const leg& other);
    		~leg();
    		leg& operator = (const leg& other);
    		...
    
    #include "leg.h"
    
    float leg::m_PI			= 3.141592f;
    float leg::m_length[4]	= {3.29f,	1.5f,	6.78f, 8.07f};
    
    leg :: leg(D3DXVECTOR3* CamPos, float x, float y, float z,  float degAngel)
    {
    	...
    }
    
    leg :: leg(const leg& other)
    {
    
    }
    leg ::~leg()
    {
    	delete m_iKin;
    }
    leg& leg :: operator = (const leg& other)
    {
    	int i;
    	m_iKin			= other.m_iKin;
    	for(i = 0; i < 4; i++)	m_angle[i]			= other.m_angle[i];
    	for(i = 0; i < 6; i++)	m_matTransform[i]	= other.m_matTransform[i];
    	for(i = 0; i < 5; i++)	m_posVec[i]			= other.m_posVec[i];
    	//for(i = 0; i < 5; i++)	m_length[4]			= other.m_length[4];
    	m_Origin		= other.m_Origin;
    	m_Target		= other.m_Target;
    	m_matRot90		= other.m_matRot90;
    	m_matTurn		= other.m_matTurn;
    	m_matDir		= other.m_matDir;
    	m_matSize		= other.m_matSize;
    	m_matAxisSize	= other.m_matAxisSize;
    	m_matTransPos	= other.m_matTransPos;
    	m_matTransSO	= other.m_matTransSO;
    	m_matTransVS	= other.m_matTransVS;
    	m_matTransOS	= other.m_matTransOS;
    	m_matTransUS	= other.m_matTransUS;
    
    	m_CamPos		= other.m_CamPos;
    	return *this;
    }
    


  • cl90 schrieb:

    ich lasse mir durch _CrtDumpMemoryLeaks(); meine Leeks anzeigen.

    leak = Leck / undichte Stelle
    leek = Lauch / Porree



  • DirkB schrieb:

    cl90 schrieb:

    ich lasse mir durch _CrtDumpMemoryLeaks(); meine Leeks anzeigen.

    leak = Leck / undichte Stelle
    leek = Lauch / Porree

    danke 😞



  • Dir scheinen Grundsätzlich noch ein paar Grundkenntnisse zu fehlen. Ein standard Konstruktor ist ein Konstruktor der keine Argumente benötigt weil er entweder keine Argumente nimmt oder alle Argumente mit default Werten belegt sind.

    Füe leg bedeutet das entweder:

    leg(D3DXVECTOR3* CamPos = nullptr, float x = 0.0f, float y = 0.0f, float z = 0.0f,  float degAngel = 0.0f)
    

    oder

    leg()
    

    Außerdem muß das delete[] aus dem Destruktor von Hexapod weg.

    Wenn du willst das Hexapod einzigartig bleibt würde ich dir empfehlen den Copy Konstruktor und den Copy Operator ins private zu setzen oder als delete zu markieren (falls dein Compiler das schon kann). Beim Move Construktor und Move Operator kannst dus dir ja überlegen.



  • Xebov schrieb:

    Dir scheinen Grundsätzlich noch ein paar Grundkenntnisse zu fehlen.

    Seh ich genauso. Für mich heisst das:

    std::vector<bein> m_bein;
    

    Konstruktoren mit nichtssagenden (und im Fall von campos auch ungültigen) Defaultwerten zu belegen halte ich für wenig sinnvoll.


Anmelden zum Antworten