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.
@ 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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?
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
structCanMsg{
2
uint8_tid;
3
uint8_tdata[6];
4
};
5
6
#define NR_MESSAGES 10
7
structCanMsgMessages[NR_MESSAGES];
8
9
structCanMsg*allocMsg()
10
{
11
uint8_ti;
12
for(i=0;i<NR_MESSAGES;i++){
13
if(Messages[i].id==0)
14
return&Messages[i];
15
}
16
17
returnNULL;
18
}
19
20
voidfreeMsg(structCanMsg*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.
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
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
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).
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.