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
@ 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.
:
Bearbeitet durch Moderator
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.
:
Bearbeitet durch User
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
:
Bearbeitet durch User
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 | 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
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
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.
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.