Forum: Compiler & IDEs malloc im AVR gcc nutzen?


von Joachim B. (jar)


Lesenswert?

ich habe noch eine Verständnisfrage zu

malloc im AVR nutzen

ist es nicht so das auch dort der Speicher fragmentiert und irgendwann 
so zerpflückt ist das nur noch reset hilft oder der MC einfach das 
arbeiten aufhört weil er keinen passenden Speicherbereich allocieren 
kann?

Früher wurde ja die Garbage Collection durchgeführt (CBM)
Bei Atari wurde der Puffer von 100 Zugriffe TOS 1.0 auf 1024 Zugriffe 
TOS 1.4 erhöht welches das Problem nur nach hinten verschob aber nicht 
löste.

also ist malloc eigentlich nutzbar? und wie würde man bei gcc eine 
garbadge collection durchführen?

Die Brutalmethode die mir einfällt ist der watchdog der den im Falle des 
Falles resetet, aber das kann doch keine saubere Programmierung sein?

Oder allokiert man gleich alle Variablen allen Speicher für alle 
Möglichkeiten und schränkt aber so den verfügbaren Stack schon bei der 
Programmierung ein? erscheint mir auch wenig sinnvoll.

: Verschoben durch Admin
von Falk B. (falk)


Lesenswert?

@ Joachim B. (jar)

>ist es nicht so das auch dort der Speicher fragmentiert und irgendwann
>so zerpflückt ist das nur noch reset hilft oder der MC einfach das
>arbeiten aufhört weil er keinen passenden Speicherbereich allocieren
>kann?

Ja.

>also ist malloc eigentlich nutzbar?

Ja, mit Einschränkungen.

> und wie würde man bei gcc eine
>garbadge collection durchführen?

Gar nicht.

>Die Brutalmethode die mir einfällt ist der watchdog der den im Falle des
>Falles resetet, aber das kann doch keine saubere Programmierung sein?

Ist es auch nicht.

>Oder allokiert man gleich alle Variablen allen Speicher für alle
>Möglichkeiten und schränkt aber so den verfügbaren Stack schon bei der
>Programmierung ein? erscheint mir auch wenig sinnvoll.

Das ist aber der gängige Weg. Bei kleinen Mikrocontrollern bringt eine 
dynamische Speicherverwaltung wenig bis nichts, eher Probleme.

von Mark B. (markbrandis)


Lesenswert?

Auf Embedded Systemen mit sehr wenig Speicher gibt es zur Laufzeit 
entweder gar keine Aufrufe von malloc(), oder aber man belegt einmal bei 
der Initialisierung den Speicher, den man brauchen wird. Wobei das nicht 
unbedingt mit malloc() geschehen muss.

von Cyblord -. (cyblord)


Lesenswert?

Joachim B. schrieb:

> Oder allokiert man gleich alle Variablen allen Speicher für alle
> Möglichkeiten und schränkt aber so den verfügbaren Stack schon bei der
> Programmierung ein? erscheint mir auch wenig sinnvoll.

Was heißt denn "für alle Möglichkeiten". Du musst ja wohl vorher 
abschätzen wieviel Speicher du max. brauchst. Sonst kann es ja auch 
sein, der RAM reicht überhaupt nicht. Und wenn du das weißt, dann kannst 
du den auch sofort statisch reservieren. Das ist der übliche Weg. 
Übriger Speicher bringt dir auch keinen Vorteil. Das ist eine völlig 
falsche Denkweise, wohl aus der PC Sparte, wo Speicher zwischen 
Prozessen aufgeteilt, und dann natürlich auch dynamisch zugewiesen und 
auch gespart werden sollte.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Falk Brunner schrieb:
> Das ist aber der gängige Weg.

Der bringt aber bei einem wirklich dynamischen Datenanfall (und nur
dann wird man malloc() überhaupt in Betracht ziehen) keineswegs
zwangsläufig eine Verbesserung: das statisch allozierte Array kann
dann genauso voll sein wie malloc() eben der Speicher ausgehen kann.
Für diesen Fall muss man also bei einem derartigen Problem immer einen
„Fluchtweg“ haben (und wenn's eben ein Reboot ist).

Ansonsten: solange man im Mittel einiges an freiem Speicher hat und
tatsächlich statistisch verteilten Datenanfall, sind die Chancen
besser als man denkt, dass das System „selbstaufräumend“ ist, d. h.
die Fragmentierung bleibt auf längere Zeit dann einigermaßen konstant.
Ist das gleiche Prinzip wie die 10 % Speicherreserve von UFS (die
ext2fs als Prinzip übernommen hat): solange man die frei hält,
defragmentiert sich das Filesystem im laufenden Betrieb selbst bzw.
hält seine Fragmentierung auf einem Niveau, welches die Benutzbarkeit
nicht behindert.

: Bearbeitet durch Moderator
von Noch einer (Gast)


Lesenswert?

Das alte DOS basierte Windows hatte dafür Speicherhandles.

Der Programmierer musste die Handles freigeben, Windows konnte den 
Speicher umsortieren, bei Bedarf musste dann der Programmierer über das 
Handle einen neuen Pointer holen.

von Joachim B. (jar)


Lesenswert?

Cyblord ---- schrieb:
> Was heißt denn "für alle Möglichkeiten".

klarer Fall, constante Strings die im Flash liegen und mit denen ich 
arbeiten will, hole mir die aus dem flash tewmporär Zeile für Zeile ins 
RAM zum weiterarbeiten und belege grad so viel RAM wie ich dort brauche, 
gebe den danach wieder frei.

Wenn ich alle für Stringkonstanten im flash gleich Ram reserviere ohne 
Not schränke ich den Stack unnötig ein.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Ein Vorteil der statischen Allokierung ist, dass du deinem Kunden Zahlen 
nennen kannst, die auf jeden Fall halten.

Hast du deinen TCP/IP Stack so eingestellt, dass er 4 Connections halten 
kann, dann kannst du das auch garantieren und bist nicht in der 
unglücklichen Lage, dass je nachdem was sonst noch so im System los ist, 
es manchmal auch nur 2 Verbindungen sind. Die zugehörigen 4 Message 
Queues hast du so eingestellt, dass jede 20 eingehende Messages halten 
kann, und das kannst du wieder garantieren, so dass es nicht vorkommen 
kann, dass dir eine Verbindung den Speicher mit Messages flutet und so 
für andere nichts mehr übrig bleibt. etc. etc.

Für so manchen Kunden ist es wichtiger, dass die zugesagten Zahlen auch 
wirklich halten, selbst wenn das bedeutet, dass man den verfügbaren 
Speicher in manchen Fällen nicht ausnutzt, weil man Speicher für Dinge 
reserviert hat, die bei diesem Kunden nicht auftreten.

von Joachim B. (jar)


Lesenswert?

Karl Heinz schrieb:
> Ein Vorteil der statischen Allokierung ist, dass du deinem Kunden Zahlen
> nennen kannst, die auf jeden Fall halten.

der Compiler prüft aber nur ob der RAM zur statischen Allokierung reicht 
nicht wie der Stack später überläuft ......

Deswegen würde ich schon bei der Programmentwicklung sparen um zur 
Laufzeit wenig Überraschungen zu erleben.

von FelixW (Gast)


Lesenswert?

Joachim B. schrieb:
> ich habe noch eine Verständnisfrage zu
>
> malloc im AVR nutzen

Die Implementierung von malloc wird von der verwendeten Library 
gestellt. Ggf verwendet man eigene Implementierungen. Malloc sollte nur 
mit bedacht ( von denken) verwendet werden.

1. Möglichkeiten: Alternative zu Stack. Globale Objekte die nie zerstört 
werden, keine Fragmentierung

2. Möglichkeit: Denselben Speicher für verschiedene Verwendungen 
erlauben. (durch malloc/free braucht meine Anwendung weniger RAM)

Lösung für 2.: Wenige Blockgrößen und allozieren von gleichen 
Blockgrößen vermeidet Fragmentierung. Speichert in möglichst großen 
Blöcken freigeben.
z.B. Betriebsmodi, die unabhängig voneinander sind.

Solange du genügend freien RAM hast lass malloc/free weg, oder erarbeite 
dir vor der Nutzung ein Konzept.

von Karl H. (kbuchegg)


Lesenswert?

Joachim B. schrieb:
> Karl Heinz schrieb:
>> Ein Vorteil der statischen Allokierung ist, dass du deinem Kunden Zahlen
>> nennen kannst, die auf jeden Fall halten.
>
> der Compiler prüft aber nur ob der RAM zur statischen Allokierung reicht
> nicht wie der Stack später überläuft ......

richtig.
Aber ein Stackverbrauch lässt sich im Regelfall ganz gut abschätzen. So 
umfangreich und voll mit Rekursionen sind die Programme für embedded 
Systeme dann meistens auch wieder nicht.

von Joachim B. (jar)


Lesenswert?

FelixW schrieb:
> 2. Möglichkeit: Denselben Speicher für verschiedene Verwendungen
> erlauben. (durch malloc/free braucht meine Anwendung weniger RAM)

du meinst die selbe Malloc Speichergröße

OK das hört sich nach einem guten Plan an

mehrere Headlines gleicher Größe reservieren 3 Zeilen max Zeilenlänge 
für alle Arten von Headlines nutzen egal wie lang oder kurz sie sind.

reserviere bei Bedarf bis zu 3 Headlines per malloc a 41 Zeichen und 
egal ob Zeile nur 10 oder 30 Zeichen hat sie passt immer und immer kann 
man freigegebene 41 Byte Ram wieder aufrufen.....

aber dann braucht man malloc nicht wirklich, reserviere ich gleich 3x 41 
Byte statisch = 123 Byte spare ich mir das malloc....

Danke dafür

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

Joachim B. schrieb:
> klarer Fall, constante Strings die im Flash liegen und mit denen ich
> arbeiten will, hole mir die aus dem flash tewmporär Zeile für Zeile ins
> RAM zum weiterarbeiten und belege grad so viel RAM wie ich dort brauche,
> gebe den danach wieder frei.

Wenn ich konstante Strings ausgeben will (oder sie als Templates für 
höhere Funktionen nehmen will, z.B. mit printf oder einer 
LCD-Bibliothek), dann kopiere ich die ohne Not garnicht erst ins RAM.

> Wenn ich alle für Stringkonstanten im flash gleich Ram reserviere ohne
> Not schränke ich den Stack unnötig ein.

Na und? Wenn du nicht gerade tiefe Rekursionen nutzt, riesige 
Abstraktionsebenen übereinander stapelst, oder große lokale Arrays 
anlegst, brauchst du nicht viel Stack. Für ungenutzten Speicher gibt es 
kein Geld zurück, weder für Stack noch Heap.

Sämtlichen Speicher statisch vorbelegen hat den Vorteil, dass der 
Compiler dir sagen kann, wieviel Stack du hast (und daraus kannst du 
dann abschätzen oder nachmessen, ob das für deine Anwendung genug ist). 
Wenn du dynamisches Zeug machen willst, kannst du auch ein Array 
statisch vorbelegen und dann mit einem eigenen malloc() als Heap 
benutzen. Auf diese Weise kannst du trotz dynamischem Speicher eine 
gewisse Stackgröße garantieren.

von dunno.. (Gast)


Lesenswert?

S. R. schrieb:
> Wenn du dynamisches Zeug machen willst, kannst du auch ein Array
> statisch vorbelegen und dann mit einem eigenen malloc() als Heap
> benutzen. Auf diese Weise kannst du trotz dynamischem Speicher eine
> gewisse Stackgröße garantieren.

Und das ganze geht sogar noch interruptsave!!1einself!

einer der hauptgründe warum ich malloc nicht mag. nur mal so in die 
diskussion geschmissen.

von Joachim B. (jar)


Lesenswert?

S. R. schrieb:
> Wenn ich konstante Strings ausgeben will (oder sie als Templates für
> höhere Funktionen nehmen will, z.B. mit printf oder einer
> LCD-Bibliothek), dann kopiere ich die ohne Not garnicht erst ins RAM.

eben NOT

mir fehlt die Info ob jede LCD LIB direkt aus dem Flash bedient werden 
kann, deswegen greife ich ich ja mit strcpy_P und dem Umweg über RAM zu 
bevor es an die LCD Lib geht.

S. R. schrieb:
> Wenn du nicht gerade tiefe Rekursionen nutzt, riesige
> Abstraktionsebenen übereinander stapelst,

eben und das weiss ich bei der Programmentwicklung nicht was später 
alles läuft und wie das ineinander greift, bin kein Informatiker und 
muss den Spagat schaffen zwischen alle Eventualitäten totprüfen und 
Programm läuft.

S. R. schrieb:
> Wenn du dynamisches Zeug machen willst, kannst du auch ein Array
> statisch vorbelegen und dann mit einem eigenen malloc() als Heap
> benutzen. Auf diese Weise kannst du trotz dynamischem Speicher eine
> gewisse Stackgröße garantieren.

hört sich interessant an, hast du Beispiele?

von Karl H. (kbuchegg)


Lesenswert?

Joachim B. schrieb:
> S. R. schrieb:
>> Wenn ich konstante Strings ausgeben will (oder sie als Templates für
>> höhere Funktionen nehmen will, z.B. mit printf oder einer
>> LCD-Bibliothek), dann kopiere ich die ohne Not garnicht erst ins RAM.
>
> eben NOT
>
> mir fehlt die Info ob jede LCD LIB direkt aus dem Flash bedient werden
> kann, deswegen greife ich ich ja mit strcpy_P und dem Umweg über RAM zu
> bevor es an die LCD Lib geht.

Ich würds mal so sagen:
solange ich den Code habe, kann ich die Funktion auch nachrüsten.

>> Wenn du dynamisches Zeug machen willst, kannst du auch ein Array
>> statisch vorbelegen und dann mit einem eigenen malloc() als Heap
>> benutzen. Auf diese Weise kannst du trotz dynamischem Speicher eine
>> gewisse Stackgröße garantieren.
>
> hört sich interessant an, hast du Beispiele?
1
struct CanMsg {
2
  uint8_t id;
3
  uint8_t data[6];
4
};
5
6
#define NR_MESSAGES 10
7
struct CanMsg Messages[NR_MESSAGES];
8
9
struct CanMsg* allocMsg()
10
{
11
  uint8_t i;
12
  for( i = 0; i < NR_MESSAGES; i++ ) {
13
    if( Messages[i].id == 0 )
14
      return &Messages[i];
15
  }
16
17
  return NULL;
18
}
19
20
void freeMsg( struct CanMsg* msg )
21
{
22
  if( msg != NULL )
23
    msg.id = 0;
24
}
25
26
....

wenn die Nutzdatengröße um einiges größer ist als ein sizeof(void*), 
dann kann man auch zuvor eine verkettete Liste aller zur Verfügung 
stehenden 'Objekte' aufbauen und die zuvor in einer Freelist miteinander 
verknüpfen. Dann spart man sich die Suche nach einem gerade freien 
Objekt.

Edit:
Man kann auch die Nutzdaten mittels einer union mit einem Pointer 
überlagern und sich so dann ebenfalls eine Freelist bauen. Hat dann auch 
den Vorteil, dass man keinen ungültigen Wert wie im obigen Beispiel 
bemühen muss.

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Edit:
> Man kann auch die Nutzdaten mittels einer union mit einem Pointer
> überlagern und sich so dann ebenfalls eine Freelist bauen. Hat dann auch
> den Vorteil, dass man keinen ungültigen Wert wie im obigen Beispiel
> bemühen muss.

Das würde dann zb so aussehen
1
struct CanMsg {
2
  uint8_t id;
3
  uint8_t data[6];
4
};
5
6
union CanFreeMsg
7
{
8
  struct CanMsg     msg;
9
  union CanFreeMsg* pNext;
10
}
11
12
#define NR_MESSAGES 10
13
struct CanFreeMsg Messages[NR_MESSAGES];
14
struct CanFreeMsg* FreeListHead;
15
16
void initMsgList()
17
{
18
  uint8_t i;
19
20
  for( i = 0; i < NR_MESSAGES - 1; i++ )
21
    Messages[i].pNext = &Messages[i+1];
22
23
  Messages[NR_MESSAGES-1].pNext = NULL;
24
  FreeListHead = Messages;
25
}
26
27
struct CanMsg* allocMsg()
28
{
29
  struct CanFreeMsg* nextFree = FreeListHead;
30
  if( FreeListHead )
31
    FreeListHead = FreeListHead->pNext;
32
33
  return (struct CanMsg*)nextFree;
34
}   
35
36
void freeMsg( struct CanMsg* msg )
37
{
38
  struct CanFreeMsg* msgFreeItem = (struct CanFreeMsg*)msg;
39
  msgFreeItem->pNext = FreeListHead;
40
  FreeListHead = msgFreeItem;
41
}
42
...


Habs jetzt nur runtergetippt. Da könnten noch Fehler drinn sein.

: Bearbeitet durch User
von Joachim B. (jar)


Lesenswert?

Karl Heinz schrieb:
> Ich würds mal so sagen:
> solange ich den Code habe, kann ich die Funktion auch nachrüsten.

gute Idee, als ich mal was am IRMP versuchte habe ich mich in  den CPU 
#defines verlaufen, also Spass macht das nicht in fremden Code einlesen.

Und welche Editoren rücken schon korrekt #ifdef und #if defined ein?

erschwerend kommt für mich hinzu, ich mag diese Schreibweise:
1
if()
2
{
3
  // bla blub
4
}
5
else
6
{
7
  // was anderes
8
}

leider schreiben viele:
1
if() {
2
  // bla blub
3
}
4
else {
5
  // was anderes
6
}

da kann man schon mal die Klammern aus den Augen verlieren

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl Heinz schrieb:
> dann kann man auch zuvor eine verkettete Liste aller zur Verfügung
> stehenden 'Objekte' aufbauen und die zuvor in einer Freelist miteinander
> verknüpfen.

Was hat es für einen Sinn, das malloc() nochmal neu zu implementieren?

Was anderes machst du ja damit auch nicht.  Dem malloc() der avr-libc
kann man auch eine feste obere Schranke zuweisen, dann hast du nichts
anderes als dein statisches Array (von ein Byte hinter bss bis zur
vorgegebenen Grenze).

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Joachim B. schrieb:
> also Spass macht das nicht in fremden Code einlesen.
Es ist aber ungemein lehrreich! Nirgends lernt man mehr als beim Lesen 
von (gutem) fremden Code!

> Und welche Editoren rücken schon korrekt #ifdef und #if defined ein?
Präprozessor-Direktiven werden idR auch nicht eingerückt

> erschwerend kommt für mich hinzu, ich mag diese Schreibweise:

siehtst du, ich mag die gar nicht. Ist in meinen Augen extreme 
Platzverschwendung. ich hasse scrollen.

> leider schreiben viele:
Ich schreib sogar noch schlimmer:
1
if() {
2
  // bla blub
3
} else {
4
   // was anderes
5
}
> da kann man schon mal die Klammern aus den Augen verlieren
Nicht wenn man viel Code gelesen hat, und etwas Erfahrung.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Und warum überhaupt malloc?

Für das, was du vorhast, würde alloca doch ausreichen.

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.