JLI Spieleprogrammierung Foren-Übersicht JLI Spieleprogrammierung

 
 FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen 
 medals.php?sid=4584b026471554e8fd2af508f69bfd58Medaillen   RegistrierenRegistrieren   ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin 

Speicherfreigabe: Calloc und Free

 
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 21.08.2008, 22:38    Titel: Speicherfreigabe: Calloc und Free Antworten mit Zitat

Gegeben ist folgende Struktur:
CPP:
struct VOXELNODE
{
   string color;               //0:=W   1:=B   2:=G
   VOXELNODE *child[8];         //Acht Teilquader bei mittiger Teilung
};



Mit den folgenen Funktionen initialisiere ich einen Octree mit Farbwerten in Form eines einfachen Strings. Mit dem Befehl "calloc" werden neue Childs erstellt.
CPP:
void CMarchingCube::LoadVoxel(string octreeStr)
{
   RootNode = (VOXELNODE *)calloc( sizeof( VOXELNODE), 1);
   RootNode->color = octreeStr.substr(0,1);

   m_iStringIndex = 0;
   m_iMaxRecDepth = 0;
   if(octreeStr.length() > 0)
   {
      LoadVoxelRec(-1, RootNode, octreeStr);
   }
}

void CMarchingCube::LoadVoxelRec(int iRecDepth, VOXELNODE* n, string octreeStr)
{
   iRecDepth++;
   if(iRecDepth > m_iMaxRecDepth)
   {
      m_iMaxRecDepth = iRecDepth;
   }

   if(n->color == "G")
   {
      //Erstelle Childnode und Prüfe weiterhin auf Kollisionen
      for(int i = 0; i < 8; i++)
      {
         m_iStringIndex++;
         if(n->child[i] == NULL)
         {
            n->child[i] = (VOXELNODE *)calloc( sizeof( VOXELNODE), 1);
            n->child[i]->color = octreeStr.substr(m_iStringIndex,1);
         }
         LoadVoxelRec(iRecDepth, n->child[i], octreeStr);
      }
   }
}



Probleme habe ich bei der Speicherfreigabe: Mir kommt es so vor als würde sie mit dem Befehl "free" überhaupt nicht greifen.

CPP:
void CMarchingCube::FreeNode(VOXELNODE *n)
{
   for(int i = 0; i < 8; i++)
   {
      if(n->child[i])
      {
         FreeNode(n->child[i]);
      }
   }
   free(n);
}


Was könnte der Fehler sein? Für meine Begriffe müsste die Zeile "free(n)" ausreichend sein, um den kompletten Speicher das Octrees wieder freizugeben.
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 437

Medaillen: Keine

BeitragVerfasst am: 22.08.2008, 01:19    Titel: Antworten mit Zitat

Nach dem ersten drüberschauen, sieht der Code gut aus.

LeeDiGer hat Folgendes geschrieben:
Mir kommt es so vor als würde sie mit dem Befehl "free" überhaupt nicht greifen.

Woran machst du das fest?

LeeDiGer hat Folgendes geschrieben:
Für meine Begriffe müsste die Zeile "free(n)" ausreichend sein, um den kompletten Speicher das Octrees wieder freizugeben.

Ähm... ich nehme an, du meinst, den kompletten Speicher eines Octrees, ohne seine Unterobjekte, dafür ist ja auch die Schleife gut. Und das stimmt soweit auch (sagt zumindest die Doku).

Also, ich sehe so spontan keinen Fehler, der verhindert, dass der Speicher freigegeben wird.
Eins hab ich aber noch anzumerken: Ich persönlich finde die Verwendung von new und delete schöner. calloc und free sind doch eher alter C-Style, new und delete stammen aus C++, und sind meiner Meinung nach intuitiver zu verwenden, als calloc. Aber das muss jeder für sich wissen, sollte nur mal so ein kleiner Hinweis am Rande sein. Wink
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 22.08.2008, 07:48    Titel: Antworten mit Zitat

Über den Taskmanager kann man den Speicherverbrauch beobachten.

Ich habs mit New und Delete mal probiert. Komischerweise klappts. Man muss nur beachten, dass man alle Zeiger mit NULL initialisiert, wenn man Abfragen mit NULL einbauen möchte. Find ich eh schon komisch, dass die Zeiger nicht automatisch schon auf NULL sind, wenn man sie neu anlegt. Egal, dann mach ich das einfach so.
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 22.08.2008, 13:25    Titel: Antworten mit Zitat

? Was meist du das sie nicht automatisch NULL sind? delete löscht nur den reservierten Speicher, auf den der Zeiger zeigt, ändert aber nichts am Zeiger selbst ... dafür schreibt man dann sowas:
CPP:
template <typename pointer_type>
inline void safe_delete(pointer_type*& pointer)
{ delete pointer; pointer = NULL; }
Wink

Wenn man mit new nen Speicher anruft, wird automatisch der Konstruktor des Datentyps aufgerufen ... oder was meinst du?

Kannst vergleich auf null schon haben, beim erstellen ...
CPP:
int* ptr_value = new (std::nothrow) int(10);
if (ptr_value == NULL) std::cerr << "FEHLER: Es konnte kein Speicher angefordert werden!";
z.B. ... aber sollte man lassen Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 22.08.2008, 21:37    Titel: Antworten mit Zitat

Nettes Konstrukt Wink
Aber ich meinte eigentlich z.B.:

CPP:
VOXELNODE* RootNode = new VOXELNODE();


Bei dieser Abfrage würde das Programm unter Umständen falsch reagieren, weil der Zeiger ja nicht mit NULL initialisiert wurde, sondern gar nicht:
CPP:
         if(n->child[i] == NULL)
         {
            n->child[i] = new VOXELNODE();
            n->child[i]->color = octreeStr.substr(m_iStringIndex,1);
            for(int k = 0; k < 8; k++)
            {
               n->child[i]->child[k] = NULL;
            }
         }



Denn bei dem "NEW"-Konstrukt muss man noch zusätzlich einfügen:

CPP:
   for(int i = 0; i < 8; i++)
   {
      RootNode->child[i] = NULL;
   }


Bei "calloc" wäre das gar nicht nötig gewesen, weil die Childs automatisch auf NULL gesetzt werden bei der initialisierung, wie es aussieht.
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 22.08.2008, 23:41    Titel: Antworten mit Zitat

Hm sorry blick dein Problem heute abend nimmer ...
CPP:
struct VOXELNODE
{
    std::string color;               //0:=W   1:=B   2:=G
    VOXELNODE* child[8];         //Acht Teilquader bei mittiger Teilung

public:
    VOXELNODE(std::string const& color)
        : color(color)
    { std::fill(child, child + 8, NULL); }
};
... wobei kopierkonstruktor usw. eigtl. auch überladen werden sollte Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 25.08.2008, 17:32    Titel: Antworten mit Zitat

das stimmt, calloc setzt bei aufruf automatisch alle bytes auf 0, ist dadurch aber auch langsamer als operator new. Wenn du das auch möchtest, solltest du dir "placement new" (->google) mal anschauen, dabei kannst du operator new und operator delete überladen und so deine eigene (klassenspezifische) Version schreiben. Wenn du willst kann ich dir ein Beispiel dazu geben.

btw:
Deviloper hat Folgendes geschrieben:
CPP:
template <typename pointer_type>
inline void safe_delete(pointer_type*& pointer)
{ delete pointer; pointer = NULL; }

ist net wirklich optimal, da ein "safe"-delete auch vor dem deleten auf 0 testen sollte, sonst ist es nicht wirklich "safe":
CPP:
template <typename T> inline void safe_delete( T& p )
{
    if( p ) delete p;
    p = 0;
}
Außerdem ist es vorteilhafter T& als T*& zu verwenden, da das Typspektrum damit auch auf Pointer-Klassen die delete implementieren erweitert wird. Das ist aber nicht zwingend notwendig.

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 25.08.2008, 18:11    Titel: Antworten mit Zitat

Was fürn Schwachsin Very Happy Sorry, aber es ist nur solange safe wie der Zeiger aufn Bereich zeigt den er löschen darf und für NULL ist definiert, dass er einfach garnichts macht. Also guck bitte erstmal im Standard nach bevor du an meinem Code rummeckerst Wink

Das einzige, was man vllt. machen könnte, wäre das mit den Referenzen, wobei ich es "ersichtlicher" finde, wenn man nen Zeiger als Parameter haben will. Aber ja, damit grenzt man das Spektrum ein Wink
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 25.08.2008, 21:01    Titel: Antworten mit Zitat

Deviloper hat Folgendes geschrieben:
Was fürn Schwachsin Very Happy Sorry, aber es ist nur solange safe wie der Zeiger aufn Bereich zeigt den er löschen darf und für NULL ist definiert, dass er einfach garnichts macht. Also guck bitte erstmal im Standard nach bevor du an meinem Code rummeckerst Wink


Ein Wink oder Very Happy Smiley wertet keine mangelnden Manieren auf, nächstes mal bitte etwas freundlicher.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Deviloper
Junior JLI'ler



Anmeldedatum: 31.05.2006
Beiträge: 77

Medaillen: Keine

BeitragVerfasst am: 26.08.2008, 15:27    Titel: Antworten mit Zitat

Sorry, etwas zu unfreundlich, hast recht. Kommt denk ich nicht wieder vor.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
DirectXer
Dark JLI'ler



Anmeldedatum: 05.02.2005
Beiträge: 1201
Wohnort: Köln
Medaillen: Keine

BeitragVerfasst am: 26.08.2008, 17:48    Titel: Antworten mit Zitat

Deviloper hat Folgendes geschrieben:
Was fürn Schwachsin :D Sorry, aber es ist nur solange safe wie der Zeiger aufn Bereich zeigt den er löschen darf und für NULL ist definiert, dass er einfach garnichts macht. Also guck bitte erstmal im Standard nach bevor du an meinem Code rummeckerst
Ahja ich sehs du hast Recht. War wohl noch wegen den alten SAFE_RELEASE makros von COM-objects bei mir hängen geblieben dass der Test auf 0 wichtig wäre. Musst aber nicht unfreundlich werden wegen sowas, wie gesagt.

Gruß DXer
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden
xardias
JLI Master


Alter: 38
Anmeldedatum: 28.12.2003
Beiträge: 804
Wohnort: Palo Alto, CA
Medaillen: Keine

BeitragVerfasst am: 26.08.2008, 21:11    Titel: Antworten mit Zitat

LeeDiGer hat Folgendes geschrieben:
Über den Taskmanager kann man den Speicherverbrauch beobachten.

Würde ich nicht so direkt als Referenzwert für solche Betrachtungen hernehmen. Wenn ich mich recht erinnere zeigt dieser an wie viel Speicher Windows dem Programm zur verfügung stellt, nicht wie viel es tatsächlich braucht.
Ich denke da dürfte ein (Memory) Profiler genauere betrachtungen erlauben.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
LeeDiGer
Super JLI'ler



Anmeldedatum: 31.08.2003
Beiträge: 366
Wohnort: Duisburg
Medaillen: Keine

BeitragVerfasst am: 05.09.2008, 13:13    Titel: Antworten mit Zitat

Es können aber Speicherlecks entstehen. Und wenn das Programm den Speicher nicht korrekt freigibt, dann sieht man auch im Taskmanager, dass sich da nix tut. Ansonsten müsste den Speicherverbrauch wieder geringer werden. Insofern würde ich schon sagen, dass man da schon was erkennen kann.
_________________
Kein Rückzug! Kein Aufgeben!
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
FH
Super JLI'ler


Alter: 36
Anmeldedatum: 16.10.2004
Beiträge: 437

Medaillen: Keine

BeitragVerfasst am: 05.09.2008, 18:09    Titel: Antworten mit Zitat

Das Problem ist
1.: Der Taskmanager gibt KB an. Das ist nicht gerade praktisch zum nachsehen, da sich Speicherleks normalerweise im Byte-Bereich bewegen, und daher man das über lange Zeit testen muss.
2.: Weiß ich nicht, wie Windows den Speicher intern handhabt. Ich könnte mir vorstellen, dass Windows aus Performance-Gründen einmal zugewiesenen Speicher dem Programm erstmal lässt, nach dem Motto, "Wenn du nochmal RAM willst, geb ich dir den gerade wieder, und muss nicht nach leeren Stellen suchen.", und erst, wenn der Speicher anderswo gebraucht wird, diesen Speicher einem anderen Programm zuweist.
Das ist halt die Frage. Ich kenne mich zu wenig mit Speichermanagern aus, um 2. beantworten zu können, aber da Windows ja auch Programme, die dynamisch Speicher reservieren immer wieder den selben Speicher zuweist (was etliche Cheat-Programme ausnutzen), könnte ich mir das schon vorstellen.
Also alles in allem ist mir der Taskmanager zu unzuverlässig um auf Speicherleks zu testen, weil ich den Code nicht kenne, der dahinter steckt (und da Win nicht OpenSource ist, werde ich das wohl auch nie).

Ich würde mir stattdessen eine RAM-Manager-Klasse schreiben. Jede RAM-Reservierung würde ich über diese Klasse laufen lassen. Und wenn dann beim beenden (also wenn der Destruktor der Klasse aufgerufen wird) das Programms noch RAM nicht wieder freigegeben wurde (was der RAM-Manager dann ja feststellen kann, schließlich lief jede RAM-Reservierung über ihn), kann man dann in irgendein Log-File schreiben, dass RAM noch nicht wieder freigegeben wurde. Das ist meiner Meinung nach zuverlässiger.
Die Idee mit dem RAM-Manager hab ich aus irgendeinem Buch geklaut, wobei ich jetzt suchen müsste, welches das war.
Aber falls du darauf bestehst, schau ich nochmal nach.
Gruß

FH
_________________
goto work, send your kids to school
follow fashion, act normal
walk on the pavement, watch T.V.
save for your old age, obey the law
Repeat after me: I am free
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Fallen
JLI MVP
JLI MVP


Alter: 40
Anmeldedatum: 08.03.2003
Beiträge: 2860
Wohnort: Münster
Medaillen: 1 (mehr...)

BeitragVerfasst am: 05.09.2008, 19:41    Titel: Antworten mit Zitat

Ich kann nur empfehlen sich einen Leakdetector zu beschaffen, zur Not den Von Windows/VC.

Ansonsten habe ich mit dem folgenden Leakdetektor wirklich gute Erfahrungen sammeln können, er schluckt selbst nicht allzuviel Speicher und kann sehr genaue Informationen dazu geben wo sich der Leak befindet:

http://www.codeproject.com/KB/applications/visualleakdetector.aspx
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    JLI Spieleprogrammierung Foren-Übersicht -> Entwicklung Alle Zeiten sind GMT
Seite 1 von 1

 
Gehe zu:  
Du kannst keine Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum nicht antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.


Powered by phpBB © 2001, 2005 phpBB Group
Deutsche Übersetzung von phpBB.de

Impressum