Servus allerseits
Wenn ich auf dem PC mit malloc arbeite, dann verhaelt es sich so, wie
man es erwartet: der freigegebene Speicherplatz wird bei der naechsten
Anforderung wiederverwendet.
PC:
Wenn ich mit gcc-arm-none-eabi (4.7.3) arbeite, habe ich ein
Verstaendnis-Problem. Der Speicherplatz wird nicht gleich
wiederverwendet, sondern erst irgendwann mal spaeter (habe diesbezüglich
einen laengeren Test als diesen hier gemacht).
1
staticchar*ptr_128,*ptr_64,*ptr_32;
2
3
ptr_128=(char*)malloc(128);// 0x200045b0
4
ptr_64=(char*)malloc(64);// 0x20004638
5
ptr_32=(char*)malloc(32);// 0x20004680
6
7
free(ptr_128);
8
free(ptr_64);
9
free(ptr_32);
10
11
ptr_32=(char*)malloc(32);// 0x20004680 <-- müsste 0x200045b0 sein
12
ptr_128=(char*)malloc(128);
13
14
free(ptr_128);
15
free(ptr_32);
16
17
ptr_128=(char*)malloc(128);// 0x20004620 <-- müsste 0x200045b0 sein
18
free(ptr_128);
malloc() funktioniert als solches zwar korrekt, aber ich versteh' nicht,
wieso er, wo doch alles Speicher zurückerstattet worden war, nicht
wieder von Anfang an Speicher vergiebt.
Der EWARM von IAR verhaelt sich übrigens so wie man es erwartet.
Hat jemand eine Erklaerung für dieses Verhalten?
Es gibt keine Vorschrift wie sich malloc() allgemein zu verhalten hat.
Das Verhalten wird von der Implementierung bestimmt und da gibt es
nunmal mehrere Möglichkeiten dies zu Implementieren.
D.h. wenn du wissen willst, wie sich malloc bei jenem Kompiler verhält,
musst du in die Dokumentation der C-Standard Bibliothek des Kompilers
(oder Platform) nachsehen.
> ptr_32 = (char *)malloc( 32); // 0x20004680 <-- müsste 0x200045b0 sein
^^^^^^
Laut wem? Deinem Bauchgefühl? Oder Wunschvorstellung? Mir jedenfalls ist
keine C-Runtime und auch kein C-Standard bekannt, der zusichern würde,
dass man irgendwelche willkürlichen Annahmen über die Rückgaben von
malloc machen darf (..die nicht spezifiziert sind ;-). Oder hast Du eine
belastbare (relevante) Quelle, die anderes behauptet?
Das ist ja mal eine lustige Annahme ... und selbst wenn es so wäre, dass
der Pointer für dieselbe, wiederholt angeforderte, Speichermenge
jedesmal derselbe sein sollte, was hätte man davon? Spätestens im Falle
mehrerer Threads könnte jederzeit ein anderer Thread Rechenzeit bekommen
und zwischendurch genau diese Adresse per malloc für seine Anforderung
wegschnappen... Das Programm, das malloc verwendet, darf sich also
niemals darauf verlassen, dass die Adresse gleich ist.
Davon mal abgesehen ist die tatsächliche physikalische Speicheradresse
im RAM-Baustein dank MMU im Prozessor wahrscheinlich sowieso jedesmal
eine andere, selbst wenn die logische Adresse, die malloc liefert
identisch sein sollte.
Ich unterstelle jetzt mal, dass sowas wie "ich nutze den Inhalt der eben
gefree'ten Adresse einfach nochmal, indem ich nochmal diesen Speicher
anfordere" gemacht werden soll ... das geht durch die MMU mit Sicherheit
sowieso daneben...
Gruß Holger
Mehmet Kendi schrieb:> nicht wieder von Anfang an Speicher vergiebt.
Vermutlich hast du ein malloc() dort, welches „eimerweise“ vergibt
und dann Anforderungen gleicher Größe vorzugsweise aus dem gleichen
„Eimer“ wieder bedient. Dadurch bekommt deine erneute Anforderung
von 32 Byte wieder den Platz, den die zuvor bereits erteilte
32-Byte-Anforderung hatte.
Nachteil: man muss mehr Speicherreserven vorhalten. Vorteil: das
Risiko einer Fragmentierung sinkt.
Um mal spaßeshalber noch ein völlig anderes System in die Runde zu
werfen, das hier passiert bei FreeBSD (Version 10.x, am64-Architektur):
Holger schrieb:> Davon mal abgesehen ist die tatsächliche physikalische Speicheradresse> im RAM-Baustein dank MMU im Prozessor wahrscheinlich sowieso jedesmal> eine andere
Bei gcc-arm-none-eabi ist davon eher nicht auszugehen.
Jörg Wunsch schrieb:> Holger schrieb:>> Davon mal abgesehen ist die tatsächliche physikalische Speicheradresse>> im RAM-Baustein dank MMU im Prozessor wahrscheinlich sowieso jedesmal>> eine andere>> Bei gcc-arm-none-eabi ist davon eher nicht auszugehen.
Wenn man aber schon C schreibt, dann sollte das so aussehen, dass
derartige Compilerabhängigkeiten keine Berücksichtigung finden. Mag ja
sein, dass das bei diesem Compiler so ist ... schön, dass DU das weißt
;) Festgelegt ist es aber nicht.
>ptr_32=(char*)malloc(32);// 0x20004680 <-- müsste 0x200045b0 sein
Der malloc() auf Deinem PC (welcher Compiler/libc ist das) scheint ein
FIFO-System zu verwenden, der malloc für Deinen µC eher ein LIFO.
Du kannst keine Annahmen darüber machen, wie und wo malloc() Speicher
allokiert. Ich nehme mal an, dass der µC-malloc sogar eine bessere
Methode verwendet: Wenn man annimmt, dass der nächste malloc() genauso
viel Speicher braucht wie der letzte free()-Aufruf freigegeben hat,
wirkt diese Methode einer Speicherfragmentierung entgegen.
> Bei gcc-arm-none-eabi ist davon eher nicht auszugehen.
und selbst wenn, wäre das mapping auch relativ konstant, weil ja nicht
jeder mit malloc() allokierte Block einzeln in physikalischen Speicher
gemappt wird, sondern seitenweise ab der jeweils ersten Verwendung,
unabhängig von malloc()- und free()-Folgen.
Natürlich, ohne daß man sich auf irgendwelche Reproduzierbarkeit
verlassen dürfte...
Wie malloc innerhalb des Programms mit seiner mir unbekannten Strategie
Speicherplatz vergibt hat mich nie interessiert.
Aber wenn alles Speicherplatz zurückerstattet worden ist, haette ich -
um g457 (Gast) zu zitieren - aus dem Bauchgefühl heraus schon erwartet,
dass malloc wieder ein "zurück zum Start" durchführt.
Mehmet Kendi schrieb:> Aber wenn alles Speicherplatz zurückerstattet worden ist, haette ich -> um g457 (Gast) zu zitieren - aus dem Bauchgefühl heraus schon erwartet,> dass malloc wieder ein "zurück zum Start" durchführt.
Wovon wir Dir mit gutem Bauchgefühl sagen können, dass Du Dich in dem
Fall mal NICHT auf Dein Bauchgefühl verlassen kannst ;)
Mehmet Kendi schrieb:> Aber wenn alles Speicherplatz zurückerstattet worden ist, haette ich -> um g457 (Gast) zu zitieren - aus dem Bauchgefühl heraus schon erwartet,> dass malloc wieder ein "zurück zum Start" durchführt.
Es gibt nicht immer ein "zurück zum Start". malloc() unter unixoiden
Systemen nutzt zum Beispiel sbrk()/brk() als Systemaufruf, um in
größeren Happen Speicher vom System zu bekommen, als Du tatsächlich vom
malloc() haben möchtest. Der einmal von malloc() benutzte Speicher wird
bei free() im allgemeinen NICHT wieder ans System zurückgegeben, sondern
bleibt für eine späterere Neu-Verwendung per malloc() weiterhin
reserviert.
Von daher ist ein "zurück zum Start" ziemlich aussichtslos. Deine
vorangegangen malloc()- und free()-Aufrufe haben das System (z.B.
RAM-Reservierung) bereits geändert.
Mehmet Kendi schrieb:> gcc-arm-none-eabi
Verwendest du ein Embedded OS? Wenn ja, verwende (wenn unbedingt nötig)
die malloc() und free() Funktionen des OS. Arbeitest du aber bare-metal,
würde ich tunlichst auf malloc() verzichten. Statische
Speicherverwaltung ist angesagt. Alles andere ist m. E. fahrlässig...
man kann von MISRA halten was man will, aber an diesem Punkt haben sie
m. E. recht.
Mehmet Kendi schrieb:> Wie malloc innerhalb des Programms mit seiner mir unbekannten Strategie> Speicherplatz vergibt hat mich nie interessiert.
Du kannst ja mal Deine
free(ptr_128);
free(ptr_64);
free(ptr_32);
umdrehen, also:
free(ptr_32);
free(ptr_64);
free(ptr_128);
Es könnte sein, dass der nächste malloc() dann anders vorgeht.
Eine Umstellung der Free-Reihenfolge hat am Verhalten nicht geaendert.
Okay, danke für all die zahlreichen Antworten. Da meine Erwartungen
bezüglich malloc nicht den Gegebenheiten zu entsprechen scheinen,
brauche ich mir dieses Verhaltens wegen keine grauen Haare wachsen zu
lassen.
Meine Befürchtung war gewesen, irgendwas sonst waere nicht ganz koscher.
Klaus Rotter schrieb:> Statische> Speicherverwaltung ist angesagt. Alles andere ist m. E. fahrlässig...> man kann von MISRA halten was man will, aber an diesem Punkt haben sie> m. E. recht.
Klaus, sorry dass ich erst jetzt darauf eingehe; war aber nicht leicht,
einen Beitrag aus dem Jaher 2008 wiederzufinden.
Beitrag "malloc/free vs. statische Variablen auf µC"
Das Ganze wurde zwar (wie in Foren so üblich) durch andere Querthemen
etwas verwaessert, aber wenn man diese ausblendet: die eigentliche
Diskussion zwischen Jörg und Yalu fand ich recht interessant.