Forum: Mikrocontroller und Digitale Elektronik Probleme mit malloc und free


von Lars (Gast)


Lesenswert?

Hallo,

hab grad Probleme mit malloc und free. Arbeite mit dem LPC1758 
Prozessor. Bei free() wird augenscheinlich nicht der komplette zuvor 
allokierte Speicher nicht wieder freigegeben.

Anbei ein kleines Testbeispiel:
1
unsigned char *GetMem(unsigned int *len)
2
{
3
  unsigned char *ptr; 
4
  ptr = (unsigned char *)malloc(sizeof(unsigned char) * *len); 
5
  if(ptr == NULL)
6
    return NULL;
7
  return ptr; 
8
}
9
10
int main(void)
11
{
12
  unsigned int length = 12; 
13
  unsigned char *ptr; 
14
15
  while(1)
16
  {
17
     ptr = GetMem(&length); 
18
     if(ptr != NULL)
19
     {
20
        //do something
21
        free(ptr); 
22
     }
23
  }
24
}

Wenn free(ptr) aufgerufen wird, werden im Speicher nur zwei Bytes auf 
0x00 zurückgesetzt, nicht die 12 Bytes.

Und nach ein paar Aufrufen hängt sich der Prozesor beim malloc() Call 
auf. Allerdings ohne einen Interrupt aufzurufen wie nen 
HardFault_Handler etc.

Mach ich bei malloc und free irgendetwas falsch?

Gruß
Lars

von PittyJ (Gast)


Lesenswert?

Wenn free(ptr) aufgerufen wird, werden im Speicher nur zwei Bytes auf
0x00 zurückgesetzt, nicht die 12 Bytes.


Warum sollte bei free() überhaupt etwas auf 0x00 gesetzt werden?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Lars schrieb:
1
>   if(ptr == NULL)
2
>     return NULL;
3
>   return ptr;

Dieses if ist unnötig, ein
1
    return ptr;

reicht hier. Wenn ptr == NULL wird auch NULL zurückgegeben ;-)

> Wenn free(ptr) aufgerufen wird, werden im Speicher nur zwei Bytes auf
> 0x00 zurückgesetzt, nicht die 12 Bytes.

Kommt auf die Implementation an. Wahrscheinlich wird der ehemals 
allokierte Bereich lediglich wieder zum erneuten Gebrauch von malloc() 
freigegeben, aber deshalb nicht unbedingt wieder frei.

> Und nach ein paar Aufrufen hängt sich der Prozesor beim malloc() Call
> auf.

Kann es sein, dass Dein erneuter Aufruf von malloc() mehr als vorher 
allokieren will? Wenn ja, kann der ehemals zur weiteren Benutzung 
freigegebene Speicherbereich evtl. nicht wieder genutzt werden und es 
wird wieder neuer Speicherplatz in Beschlag genommen. Das heisst: Du 
fragmentierst Dir mit der Zeit Deinen Speicher.

malloc() und free() sind auf nicht pagenden Systemen nur mit Vorsicht 
anzuwenden. Bei µCs würde ich sie eher meiden.

P.S.

Ich weiß nicht genau, warum Du einen Pointer auf length runtergibst und 
dann dieses Konstrukt

  malloc(sizeof(unsigned char) * *len);

verwendest.

Rufe GetMem() mit length auf und benutze

  malloc(len);

: Bearbeitet durch Moderator
von Lars (Gast)


Lesenswert?

Frank M. schrieb:
> malloc() und free() sind auf nicht pagenden Systemen nur mit Vorsicht
> anzuwenden. Bei µCs würde ich sie eher meiden.

das vermute ich auch. Der obige Code ist stark vereinfacht. Ich glaub 
ich habe eine Sache übersehen und zwar tritt der Fehler bei malloc nur 
dann auf, wenn ich zweimal hintereinander speicher allokiere.
1
unsigned char *GetMem(unsigned int *len)
2
{
3
  unsigned char *ptr; 
4
  ptr = (unsigned char *)malloc(sizeof(unsigned char) * *len); 
5
  if(ptr == NULL)
6
    return NULL;
7
  return ptr; 
8
}
9
10
void test(void)
11
{
12
  unsigned char *ptr2; 
13
  unsigned short number = 23; 
14
  ptr2 = (unsigned char *)malloc(sizeof(unsigned char) * number); 
15
  free(ptr2); 
16
}
17
18
int main(void)
19
{
20
  unsigned int length = 12; 
21
  unsigned char *ptr; 
22
23
  ptr = GetMem(&length);
24
  free(ptr); 
25
  //<- diese Aufrufe funktionieren und es werden 12 bytes auf 0x00
26
  //im speicher gesetzt 
27
28
  while(1)
29
  {
30
     ptr = GetMem(&length); 
31
     if(ptr != NULL)
32
     {
33
        test(); 
34
        free(ptr);  //hier werden nur noch vier bytes auf 0x00 gesetzt
35
                    //die ersten vier Bytes 
36
     }
37
  }
38
}

Beispiel: für ptr wird 0x100009C8 zurückgegeben nach malloc und für ptr2 
wird ebenfalls als Startaddr von malloc 0x100009C8 zurückgegeben...

Scheint überhaupt nicht zu funktionieren

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ich kürze mal Deinen Source, weil hier viel Überflüssiges die Sicht 
vernebelt:
1
void test(void)
2
{
3
  unsigned char *ptr2; 
4
  unsigned short number = 23; 
5
  ptr2 = (unsigned char *)malloc(number); 
6
  free(ptr2); 
7
}
8
9
int main(void)
10
{
11
  unsigned int length = 12; 
12
  unsigned char *ptr; 
13
14
  ptr = malloc(length);
15
  free(ptr); 
16
  //<- diese Aufrufe funktionieren und es werden 12 bytes auf 0x00
17
  //im speicher gesetzt 
18
19
  while(1)
20
  {
21
     ptr = malloc(length);
22
     if(ptr != NULL)
23
     {
24
        test(); 
25
        free(ptr);  //hier werden nur noch vier bytes auf 0x00 gesetzt
26
                    //die ersten vier Bytes 
27
     }
28
  }
29
}

Was habe ich geändert:

1. Den Pointer beim Aufruf von GetMem() ersetzt durch den Wert von
   length, denn hier ist kein Pointer notwendig.

2. die Konstruktion sizeof (sizeof(unsigned char) * *len) durch (len)
   ersetzt, denn die Multiplikation ist unsinnig. Du willst length
   Bytes.

3. Deine NULL-Pointer-Abfrage in GetMem() komplett gestrichen.

4. Letztendlich GetMem() komplett rausgeworfen, denn nun macht es
   nichts anderes mehr als malloc() selbst.

Dass irgendwann 12 Bytes und später mal 4 Bytes im Speicher auf 0x00 
gesetzt werden, ist kein Kriterium für korrekte/inkorrekte 
Funktionalität. malloc() erhebt keinen Anspruch darauf, den allokierten 
Speicher auch zu löschen. Das macht nur calloc(). Bei malloc() ist der 
Inhalt des allokierten Speichers undefiniert.

> Beispiel: für ptr wird 0x100009C8 zurückgegeben nach malloc und für ptr2
> wird ebenfalls als Startaddr von malloc 0x100009C8 zurückgegeben...

Das gibt mir allerdings zu denken. Dürfte nicht sein.

Ich kürze mal weiter:
1
int main(void)
2
{
3
  unsigned char *ptr; 
4
  unsigned char *ptr2; 
5
6
  ptr = malloc(12);
7
  free(ptr); 
8
9
  while(1)
10
  {
11
     ptr = malloc(12);
12
13
     if(ptr != NULL)
14
     {
15
        ptr2 = malloc(23);  // ist hier nun ptr == prtr2?
16
        free(ptr2);
17
        free(ptr);
18
     }
19
  }
20
}

Ist an der markierten Stelle nun ptr == ptr2 ?

: Bearbeitet durch Moderator
von Fred (Gast)


Lesenswert?

Lars schrieb:
> sizeof(unsigned char)

Ist gleich 1 per Definition. Aus der Multiplikation also wegfallen 
lassen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.