malloc und free



  • Hi,

    wenn ich mit malloc - für z.b. ein array a - speicher reserviere, was passiert mit dem reservierten speicher, wenn ich nochmal malloc anwende und zwar auf das gleiche array a. Wird der Speicher dann wieder freigegeben un neu alloziert oder muss ich free verwenden, um den speicher wieder freizugeben? Wenn ja, wie kann ich prüfen ob ich schon irgendwann mal speicher alloziert hatte?

    MFG bham



  • ein zweites mal malloc auf dem gleichen zeiger macht den vorher reservierten speicherplatz ungzugänglich.
    der speicherplatz existiert dann noch, aber du kommst nicht mehr ran, weil die adresse nicht mehr bekannt ist.

    wenn du den speicherplatz nicht mehr brauchst, dann kannst du free aufrufen.
    möchtest du den speicherplatz vergrößern, steht dir realloc zur verfügung, die gespeicherten elemente bleiben erhalten.

    du kannst prüfen, ob du speicher reserviert hast, indem du malloc in eine funktion einbettest, die jeden malloc aufruf speichert.



  • bham schrieb:

    wenn ich mit malloc - für z.b. ein array a - speicher reserviere, was passiert mit dem reservierten speicher, wenn ich nochmal malloc anwende und zwar auf das gleiche array a. Wird der Speicher dann wieder freigegeben un neu alloziert oder muss ich free verwenden, um den speicher wieder freizugeben?

    du musst zuerst 'free' verwenden. ein zweites 'malloc' macht das erste nicht rückgängig. du könntest natürlich was mit 'realloc' basteln, dann brauchste nur ein 'free' am schluss.

    bham schrieb:

    Wenn ja, wie kann ich prüfen ob ich schon irgendwann mal speicher alloziert hatte?

    setz einfach beim anlegen und nach dem free den pointer auf 0. dann weisst du immer, wenn er !=0 ist, dass speicher alloziert wurde.
    🙂



  • bham schrieb:

    wenn ich mit malloc - für z.b. ein array a - speicher reserviere, was passiert mit dem reservierten speicher, wenn ich nochmal malloc anwende und zwar auf das gleiche array a.

    das, was du da erzählst ist nicht machbar, denn malloc kann nicht auf etwas angewandt werden, denn das einzige Parameter von malloc ist eine Zahl (und kein Pointer). Wenn du meinst sowas:

    void *p = malloc(19999);
    p = malloc(10);
    

    du speicherst in p nur die Adresse, die malloc zurückgibt. Woher soll malloc an der 2. Stelle wissen, dass du nocheinmal p zuweist oder überhaupt worauf p zeigt? Das ist sowieso malloc egal, weil malloc nur freien Speicher für die reserviert. Im obigen Fall verliere ich Adresse der 19999 reservierten Bytes und kann auf sie nicht mehr zugreifen.



  • und wenn ich malloc für lokale variablen in funktionen verwende und dann die funktion beendet ist, wird auch nichts automatisch freigegeben? sprich ich müsste in der funktion, bevor sie beendet auch ein free haben, ja?

    Wie ist das wenn das ganze programm beendet wird? werden dann die allokierten bereiche freigegeben oder kann man über die zeit seinen speicher damit blockieren?

    @ supertux: jo is klar. hab ich mich ungeschickt ausgedrückt



  • bham schrieb:

    Wie ist das wenn das ganze programm beendet wird? werden dann die allokierten bereiche freigegeben oder kann man über die zeit seinen speicher damit blockieren?

    kommt auf dein OS an. unter windose z.b. hat jeder prozess seinen eigenen heap. wenn das programm beendet wird, wird alles automatisch wieder freigegeben, egal wieviele 'frees' du vergessen hast. macht dein programm über längere zeit viele 'mallocs' und gibt nie was frei, dann kann dein system allerdings sehr träge werden, weil dem OS freies RAM ausgeht und bei jedem speicherzugriff das paging-file bemüht werden muss.
    🙂



  • bham schrieb:

    und wenn ich malloc für lokale variablen in funktionen verwende und dann die funktion beendet ist, wird auch nichts automatisch freigegeben? sprich ich müsste in der funktion, bevor sie beendet auch ein free haben, ja?

    Wie ist das wenn das ganze programm beendet wird? werden dann die allokierten bereiche freigegeben oder kann man über die zeit seinen speicher damit blockieren?

    Das ist (wie vista erklärt hat) eine OS Sache. In der C Sprache ist sowas nicht eingebaut oder definiert. Ich kenne den Wortlaut des Standards nichts, deswegen hier meine Vermutung: der Compiler weiß nichts über die Semantik der Funktionen, kann also nicht wissen, dass bei

    void foo(void)
    {
      void *ptr = mallo(19);
    }
    

    ptr auf reservierten Speicherbereich zeigt. Demnach kann er nicht entscheiden, ob am Ende von 'foo()' den Speicher freigeben soll. Und selbst wenn, müsste er von 'free()' wissen.



  • ^^deshalb gibt es z.b. systeme (D, Java, .NET, Python usw.) mit eingebautem 'garbage collector'. der erkennt selbständig, wenn ein speicherblock nicht mehr benötigt wird und 'freed' ihn automatisch. andere haben libraries mit workarounds dafür wie z.b. C++ mit 'auto_ptr' und ähnlichem. C ist low-level und hat das alles nicht d.h. malloc und free sind einfach nur library-funktionen und der benutzer ist für den richtigen gebrauch selbst verantworlich.
    🙂



  • Ok, also kann man generell sagen: Jedem malloc sollte irgendwo ein free folgen.

    Wie ist das mit statischen arrays? z.b.:

    int char[10];
    

    das würde ja implizit auch speicher reservieren, weil man könnte ja genausogut schreiben:

    int *char;
    char = malloc(10*sizeof(char));
    

    muss ich also arrays auch mit free traktieren?

    Ist es generell ein designfehler, wenn funktionen variablen zurückgeben, die dynamisch speicher zugewiesen bekommen haben? Man kann dann ja nicht garantieren, dass irgendjemand wieder ein free dafür verwendet.



  • bham schrieb:

    Ok, also kann man generell sagen: Jedem malloc sollte irgendwo ein free folgen.

    Einfach ausgedrückt: Ja.

    bham schrieb:

    Wie ist das mit statischen arrays? z.b.:

    int char[10];
    

    "Statisches Array" ist etwas mißverständlich, es könnte auch sowas gemeint sein:

    static int[10];
    

    Du beziehst das "statisch" ja aber auf die fixe 10.

    bham schrieb:

    das würde ja implizit auch speicher reservieren, weil man könnte ja genausogut schreiben:

    int *char;
    char = malloc(10*sizeof(char));
    

    muss ich also arrays auch mit free traktieren?

    Nein. Arrays kommen entweder auf den Stack oder ins Datensegment. Im Datensegment leben die Variablen von (vor) Beginn des Programms, bis zu dessen Ende. Auf dem Stack leben die Variablen bis zum Ende des Blocks.
    Mit malloc() dagegen wird Speicher auf dem Heap angefordert. Dieser lebt bis du ihn wieder freigibst (oder das OS nach Ende des Programms aufräumt). Du solltest die Speicherklassen nochmal im Buch nachlesen.

    bham schrieb:

    Ist es generell ein designfehler, wenn funktionen variablen zurückgeben, die dynamisch speicher zugewiesen bekommen haben? Man kann dann ja nicht garantieren, dass irgendjemand wieder ein free dafür verwendet.

    Nicht generell. Pauschal kann man das nicht sagen. Ich beschränke das eigentlich immer auf Konstruktoren die dann auch einen dedizierten Destruktor haben.[/quote]



  • ok, dann ist mir das jetzt - glaube ich - klar. Aber weil ichs nur glaube:
    Gibt es ein programm, was memory leaks erkennt? oder anders: wie kann ich denn am ende sicher sein, dass ich alles wieder freigegeben habe was ich mal reserviert habe? Was ist da die beste methode?



  • Unter Linux kann ich valgrind empfehlen. Allgemein (portabel) kannst du malloc() und free() wrappen und einfach bei malloc() einen Zähler inkrementieren und bei free() wieder dekrementieren.

    (irgendwie habe ich das alles im halbfertigen FAQ-Prototypen... den sollte ich echt mal fertigmachen :()



  • bham schrieb:

    Ist es generell ein designfehler, wenn funktionen variablen zurückgeben, die dynamisch speicher zugewiesen bekommen haben?

    Nein, sonst wären malloc & friends Designfehler 😉

    Wenn du eine Funktion anbietest, die dynamischen Speicher reserviert und zurückliefert, dann obliegt es an dir, in der Dokumentation darauf hinzuweisen, dass der Benutzer den reservierten Speicher freigeben muss (oder eine bestimmte Funktion aufrufen soll, die den Speicher aufräumt). Mehr kannst du da nicht machen.



  • Tim schrieb:

    (irgendwie habe ich das alles im halbfertigen FAQ-Prototypen... den sollte ich echt mal fertigmachen :()

    Done: http://www.c-plusplus.net/forum/viewtopic-var-t-is-206606.html



  • Tim schrieb:

    Done: http://www.c-plusplus.net/forum/viewtopic-var-t-is-206606.html

    if ( temp != NULL )
    

    Wieso testest Du bei realloc explizit? NULL ist doch 0 ist doch boolean 0.

    Weitergehend: Der Wrapper ist zwar lustig, aber der echte Speicherverbrauch ist ja auch interessant (besonders, wenn's knapp wird) - scheitert wohl daran, daß man free() nicht entlocken kann, wieviel es freigegeben hat - oder?



  • pointercrash() schrieb:

    Weitergehend: Der Wrapper ist zwar lustig, aber der echte Speicherverbrauch ist ja auch interessant (besonders, wenn's knapp wird) - scheitert wohl daran, daß man free() nicht entlocken kann, wieviel es freigegeben hat - oder?

    kannste so machen, wenn du mitzählen willst:

    #include <stdio.h>
    #include <stdlib.h>
    
    size_t total = 0;
    
    void *my_malloc (size_t s)
    {
      size_t *i = malloc (s + sizeof(int));
      if (!i)
      {
        printf ("heap exhausted");
      }
      else
      {
        *i = s;
        total += s;
        printf ("%u/%u bytes malloc'd\n", s, total);
      }
      return i+1;
    }
    
    void my_free (void *p)
    {
      size_t *i;
      if (p)
      {
        i = p;
        i--;
        total -= *i;
        printf ("%u/%u bytes freed\n", *i, total);
        free (i);
      }
    }
    
    int main() // demo
    {
      int *p = my_malloc (10*sizeof(*p));
      double *q = my_malloc (12*sizeof(*q));
    
      my_free (p);
      my_free (q);
    }
    

    🙂



  • ääh, kleiner fehler, in der zeile: size_t *i = malloc (s + sizeof(int));
    muss das sizeof so sein: sizeof(size_t)
    🙂



  • pointercrash() schrieb:

    Wieso testest Du bei realloc explizit? NULL ist doch 0 ist doch boolean 0.

    Hmm, ich denke um es eindeutig zu machen. Geschmackssache. Normalerweise mach ich das auch nicht.

    pointercrash() schrieb:

    Weitergehend: Der Wrapper ist zwar lustig, aber der echte Speicherverbrauch ist ja auch interessant (besonders, wenn's knapp wird) - scheitert wohl daran, daß man free() nicht entlocken kann, wieviel es freigegeben hat - oder?

    Jo, das Ding sollte erstens nicht zu weit führen, und zweitens portabel sein. Und dann müsste man für jede Allokation gleich noch in einer Liste merken was man man reserviert hat, etc. Dazu sind dann Tools wie valgrind besser.



  • fehlerteufel-freak schrieb:

    ääh, kleiner fehler, in der zeile: ... 🙂

    Den hätte ich sogar gesehen 😉 , mir ist aber nicht ganz klar, was im free- wrapper in den Zeilen

    i = p;
    

    wirklich passiert. Da wird ein void* implizit auf size_t* gecastet und und schwuppdiwupp kriege ich darüber die Größeninformation?
    Wo ist der Gimmick, den ich jetzt nicht abraffe? 😕

    Kannst Du's mir schonend beibringen?



  • pointercrash() schrieb:

    Wo ist der Gimmick, den ich jetzt nicht abraffe? 😕

    Kurz: Er reserviert immer ein size_t mehr Speicher als angefordert, dort speichert er die reservierte Länge ab und gibt dann einen Zeiger auf das nächste Element weiter. Beim free() halt dann rückwärts.


Anmelden zum Antworten