Forum: Mikrocontroller und Digitale Elektronik Automatische Variable vs. malloc()


von Walter T. (nicolas)


Lesenswert?

Hallo zusammen,

ich habe eine Funktion callee(), bei der Daten zwischen den Aufrufen 
"gemerkt" werden müssen. Aufgrund der schieren Datenmenge und weil sie 
später nicht mehr benötigt werden, will ich diesen Daten nicht dauerhaft 
Speicherplatz mit static geben oder eine globale Variable daraus machen. 
Aufgrund der Struktur der aufrufenden Funktion caller() muss sie eine 
void-void-Funktion bleiben. Also muß ich den Speicherplatz in der 
aufrufenden Funktion reservieren und später wieder freigeben.

Dabei kann ich mir zwei Varianten vorstellen:

a) Mittels automatischen Variablen
b) Mittels malloc()/free()

Im Pseudo-Quelltext sähe das so aus:
1
typedef struct
2
{
3
    uint64_t a, b, c, d, e, f, g, h, i, j, k, l, m, n;
4
}
5
SomeLargeStruct_t;
6
7
8
SomeLargeStruct_t *LargeStructPtr;
9
10
11
/* Callee function needs to be void-void function, will only be called by caller() */
12
void callee(void)
13
{
14
    assert( LargeStructPtr != NULL );
15
    SomeLargeStruct_t *Data = LargeStructPtr;
16
17
    //Do something you like with it [...]
18
19
}
20
21
22
/* caller() cannot be changed */
23
void caller(void)
24
{
25
    // [...] I will do some complicated stuff here
26
    callee();
27
    // [...] I will do some more complicated stuff
28
}
29
30
31
/* Automatic variable */
32
void fooAuto(void)
33
{
34
    SomeLargeStruct_t Data;
35
    LargeStructPtr = &Data;
36
37
    while( manyManyIterations )
38
    {
39
        caller();
40
    }
41
42
    LargeStructPtr = NULL;
43
}
44
45
46
47
/* Malloc */
48
void fooMalloc(void)
49
{
50
    LargeStructPtr = malloc(sizeof(SomeLargeStruct_t));
51
52
    while( manyManyIterations )
53
    {
54
        caller();
55
    }
56
57
    free(LargeStructPtr);
58
}

Vorausgesetzt, dies ist nicht der einzige Aufruf von malloc() im 
gesamten Programm (d.h. ich spare schon einmal nicht diesen Teil der 
stdlib): Hat eine dieser Varianten Vorteile, oder ist das 
Geschmackssache?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Walter T. schrieb:
> will ich diesen Daten nicht dauerhaft Speicherplatz mit static geben
> oder eine globale Variable daraus machen.

Verwende einen /static/-Pointer in Deiner Funktion um das Ergebnis von 
malloc aufzuheben. Ist der Pointer NULL, muss malloc aufgerufen werden, 
ist er nicht NULL, kann der Speicher verwendet werden.

Du brauchst jetzt nur noch eine Möglichkeit schaffen, den Speicher nach 
Gebrauch wieder loszuwerden, d.h. Du musst Deine Funktion so aufrufen 
können, daß sie erkennt, daß sie den Speicher mit free freigeben soll.

von Bärenmarke (Gast)


Lesenswert?

Ich würde die automatische Variable nehmen:
- Kein malloc () nötig
- Keine Chance, free () zu vergessen

Bevorzugen würde ich allerdings eine Variante,
die den Zeiger als Funktionsparameter durchreicht.
Deine Erklärung in dem Punkt ist mir schleierhaft,
sorry :-)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bärenmarke schrieb:
> Ich würde die automatische Variable nehmen:

Lebt nur während der Laufzeit der Funktion und enthält beim nächsten 
Aufruf nicht die Daten des letzten Durchlaufs, was aber gefordert wird:

Walter T. schrieb:
> bei der Daten zwischen den Aufrufen "gemerkt" werden müssen.

Braucht obendrein Platz auf dem Stack, und zwar offensichtlich viel :

> Aufgrund der schieren Datenmenge ...

von Jemand (Gast)


Lesenswert?

Walter T. schrieb:
> Aufgrund der Struktur der aufrufenden Funktion caller() muss sie eine
> void-void-Funktion bleiben.

Versuch diese verpfuschte Funktion umzustrukturieren.

von Bärenmarke (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Lebt nur während der Laufzeit der Funktion und enthält beim nächsten
> Aufruf nicht die Daten des letzten Durchlaufs, was aber gefordert wird:
>
> Walter T. schrieb:
>> bei der Daten zwischen den Aufrufen "gemerkt" werden müssen.

Ich bin vom Pseudocode ausgegangen. Die Struct "lebt" im Stack von 
fooAuto().

Rufus Τ. F. schrieb:
> Braucht obendrein Platz auf dem Stack, und zwar offensichtlich viel :
>
>> Aufgrund der schieren Datenmenge ...

Platz braucht es überall, aufgrund der schieren Datenmenge :-)

von Bärenmarke (Gast)


Lesenswert?

Jemand schrieb:
> Versuch diese verpfuschte Funktion umzustrukturieren.

ACK!

von Pandur S. (jetztnicht)


Lesenswert?

Ich wuerde eine globale Array Variable verwenden, die hinreichend gross 
ist um alles zu beinhalten. Das erspart irgendwelche dynamischen 
Speicherreservierungen

von mikro (Gast)


Lesenswert?

Walter T. schrieb:
> Hat eine dieser Varianten Vorteile, oder ist das
> Geschmackssache?

Der Stackgröße ist häufig "begrenzt". Auf einigen Architekturen 
tatsächlich, auf anderen durch das OS mit (einstellbaren) Hard- und 
Softlimits.

von foobar (Gast)


Lesenswert?

Dass das ein UglyHack™ ist, wissen wir wohl alle.  Wenn's aber nicht 
anders geht, würde ich immer die auto-Variante wählen, evtl noch mit 
einem zusätzlichen assert(Ptr==NULL) in fooAuto.  Die malloc-Variante 
bieten keinerlei Vorteile, braucht nur zusätzlichen Speicher, mehr 
Rechenzeit und fragmentiert den Heap.

von Walter T. (nicolas)


Lesenswert?

Bärenmarke schrieb:
> Bevorzugen würde ich allerdings eine Variante,
> die den Zeiger als Funktionsparameter durchreicht.

Ich auch. Aber callee() ist eine callback-Funktion, deren Signatur durch 
das aufrufende System bestimmt wird. Wie eine ISR.

foobar schrieb:
> Dass das ein UglyHack™ ist, wissen wir wohl alle.

Warum eigentlich? Wie sieht die saubere Variante aus, wenn 
Callback-Funktionen oder ISRs und ihre Variablen nur in einem genau 
bestimmten, zeitlich begrenzten Rahmen benötigt werden?

von Karl (Gast)


Lesenswert?

Walter T. schrieb:
> Ich auch. Aber callee() ist eine callback-Funktion, deren Signatur durch
> das aufrufende System bestimmt wird. Wie eine ISR.

D.h. du weißt ganz genau wann die Struktur benötigt wird. Schon Mal gut.

Die eine Frage die sich mir stellt: Machst du was sinnvolles mit dem 
nicht verwendeten Speicher?
Du musst ihn so wie so irgendwo vorhalten. Sei es durch einen 
entsprechend großen Stack oder einen entsprechend großen Heap oder eine 
globale Variable.
Der Fall bei dem sich die dynamische allokierung lohnt, ist wenn man 
mehrere ähnliche Strukturen zu unterschiedlichen Zeiten braucht. Aber 
auch das ließe sich mit Unions statisch lösen. Oder halt wenn der 
Speicherbedarf an Stack deines Programms später noch in eine ähnliche 
Größenordnung anwächst.

Obwohl ich kein großer Fan von sehr großen Datenmengen auf dem Stack 
bin, würde ich in deinem Fall vermutlich auch so machen, wenn ein malloc 
nicht einfach verfügbar ist. Man muss sich aber der Anforderungen an den 
Stack bewusst sein.
Für die malloc Variante spricht mMn die explizite Kommunikation, dass 
hier etwas speicherlastiges passiert. Weiter kann bei Speichermangel die 
Kontrolle über das Programm behalten werden. Wenn dein Stack überläuft 
merkst du das meistens an ganz anderer Stelle im Programm. So gesehen 
finde ich malloc besser.

von Walter T. (nicolas)


Lesenswert?

Karl schrieb:
> Die eine Frage die sich mir stellt: Machst du was sinnvolles mit dem
> nicht verwendeten Speicher?

Die Frage ist gut, und die ehrliche Antwort lautet: Nein. Momentan ist 
alles als dauerhafte, globale Variable angelegt und es funktioniert 
alles.

Was mich daran stört: Die Funktionen, die diesen Speicherplatz belegen, 
werden extrem selten benutzt. Sie werden in einem interaktiven 
Nutzermenü (deswegen die fixe Signatur) verwendet, das vermutlich 
einmalig beim Einrichten des Systems benötigt wird und helfen beim 
Tuning einiger Parameter. Oder auch nie. Man kann auch anders 
einstellen.

a) Irgendwie widerspricht es meinem Ordnungssinn, dass ein großer Teil 
des Speichers von einer nie genutzten Funktion belegt wird.

b) Sobald ich eine zweite, ähnliche Funktion schreibe, wird es wirklich 
eng.

von Joe F. (easylife)


Lesenswert?

Walter T. schrieb:
> Was mich daran stört: Die Funktionen, die diesen Speicherplatz belegen,
> werden extrem selten benutzt. Sie werden in einem interaktiven
> Nutzermenü (deswegen die fixe Signatur) verwendet, das vermutlich
> einmalig beim Einrichten des Systems benötigt wird und helfen beim
> Tuning einiger Parameter. Oder auch nie. Man kann auch anders
> einstellen.
>
> a) Irgendwie widerspricht es meinem Ordnungssinn, dass ein großer Teil
> des Speichers von einer nie genutzten Funktion belegt wird.

Im Prinzip ist für solche Fälle malloc()/free() der richtige Weg, 
zumindest auf von Menschen bedienten Computern.
Wenn der Speicher zu knapp ist, bekommt man eine Fehlermeldung, dass das 
Programm nicht ausgeführt werden kann und der Benutzer kann reagieren 
(andere Programme schließen, den Rechner aufrüsten etc.).

Bei Mikrocontrollersystemen gibt es diese Möglichkeit nicht. Das Menü 
muss angezeigt werden können, egal was nebenbei sonst noch passiert.
Wenn du also genau absehen kannst, dass das Menu nur dann angezeigt 
wird, wenn auch 100%ig genug Speicher zur Verfügung steht, dann kann man 
malloc() verwenden, um danach diesen Speicher anderweitig nutzen zu 
können.
Wann das nicht sicherstellbar ist, würde ich den Speicher dauerhaft 
reservieren (auf dem Stack), und der Compiler stellt sicher, dass deine 
Firmware zu jeder Zeit genügend Speicher hat, um fehlerfrei ausgeführt 
zu werden.
Sieht erstmal nach "Speicherverschwendung" aus, der selten genutzte 
Speicher wird aber benötigt, damit das Programm immer funktioniert.

von Peter D. (peda)


Lesenswert?

Malloc/free bringt auf nem MC nur dann was, wenn sich Funktionen 
gegenseitig ausschließen, die es benutzen. Ansonsten muß Du eh den 
maximal nötigen Speicher vorhalten, kannst ihn also gleich fest 
vergeben.

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

Walter T. schrieb:
...
> Die Frage ist gut, und die ehrliche Antwort lautet: Nein. Momentan ist
> alles als dauerhafte, globale Variable angelegt und es funktioniert
> alles.
...

Wenn Du die volle Malloc-Funktionalität nicht brauchst, könntest Du Dir 
abgespeckte Varianten anschauen. Aus dem Stegreif glaube ich mich zu 
erinnern, dass z.B. Adam Dunkels lwIP und Elm Chans FAT eine eigene 
Speicherverwaltung aufziehen.

Ich bin auch kein bedingungsloser Fan von dynamischer 
Speicherallokierung auf kleinen Maschinen, deswegen finde ich solche 
Ansätze fallweise interessant.

von Karl (Gast)


Lesenswert?

Walter T. schrieb:
> a) Irgendwie widerspricht es meinem Ordnungssinn, dass ein großer Teil
> des Speichers von einer nie genutzten Funktion belegt wird.
>
Ist klar. Das geht den meisten von uns so.
> b) Sobald ich eine zweite, ähnliche Funktion schreibe, wird es wirklich
> eng.
Das wäre imo DER Anwendungsfall für eine Union. Alles statisch und 
trotzdem im Rahmen der Abwertung ausreichend flexibel.

Schlussendlich ist es persönlicher Geschmack. Meine Argumente pro malloc 
stehen oben. Der Rest hat sicher auch entsprechende Beweggründe.

Zur Einschätzung meines Kommentars: Ich habe kommerzielle Anwendungen im 
Feld, die in c++ mit dynamischem Speicher und rein virtuellen Klassen 
arbeiten. Natürlich auf einem uC. Nach der Meinung einiger hier habe ich 
damit den Weltuntergang ausgelöst... Tatsächlich hat diese Entscheidung 
viel Arbeit bei der Entwicklung gespart weil es für meinen 
Anwendungsfall natürlich war. Das kommt aber immer auf den Einzelfall 
an. Will nur sagen: Keine Angst!

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> Malloc/free bringt auf nem MC nur dann was, wenn sich Funktionen
> gegenseitig ausschließen, die es benutzen.

Genau. Das ist ja hier der Fall.

Meine ursprüngliche Fragestellung war ja: "malloc() oder automatische 
Variable - wo liegen die Vor- und Nachteile?" Was ja irgendwie auf die 
Frage entspricht: "Stack oder Heap - wo liegen die Vor- und Nachteile?".

Meine naive Denkweise war erst einmal: Solange ich keinen Speicherschutz 
und kein Betriebssystem habe, ist das egal.

Bei der automatischen Variable kann ich kein free() vergessen, dafür muß 
ich von Hand dafür sorgen, daß der Zeiger auf keine ungültige Variable 
zeigt. Das kommt von den Verwaltungs-Hausaufgaben auf das Gleiche 
heraus.

Bei malloc() muß ich die entsprechenden Funktionen der stdlib mit 
dazulinken. Ist aber sowieso schon drin, weil es an anderer Stelle 
gebraucht wird. Kommt also auch aufs Gleiche heraus.

Habe ich etwas vergessen?

von Karl (Gast)


Lesenswert?

Joe F. schrieb:
> Bei Mikrocontrollersystemen gibt es diese Möglichkeit nicht.
Naja. Display ist doch da...
> Wann das nicht sicherstellbar ist, würde ich den Speicher dauerhaft
> reservieren (auf dem Stack), und der Compiler stellt sicher, dass deine
> Firmware zu jeder Zeit genügend Speicher hat, um fehlerfrei ausgeführt
> zu werden.
Da passt was nicht. Stack ist dynamisch und zur Compilerzeit nicht immer 
oder auch überhaupt nicht zu analysieren. Den Compiler kümmert das 
nicht. Du meinst vermutlich das Datensegment?
> Sieht erstmal nach "Speicherverschwendung" aus, der selten genutzte
> Speicher wird aber benötigt, damit das Programm immer funktioniert.
Nö. Man Stelle sich vor es gäbe 10 dieser Menüs die aber nur exclusiv 
aktiv sein können. Da ist jede der dynamischen Varianten geeignet um das 
Programm überhaupt zum Laufen zu bekommen

von Rolf M. (rmagnus)


Lesenswert?

Karl schrieb:
> Joe F. schrieb:
>> Bei Mikrocontrollersystemen gibt es diese Möglichkeit nicht.
> Naja. Display ist doch da...

Nun würde ich bei einem Embedded-Gerät nicht unbedingt erwarten, dass 
beim Versuch, ein Menü zu öffnen, die Meldung kommt, dass dafür gerade 
kein Speicher frei ist.

>> Wann das nicht sicherstellbar ist, würde ich den Speicher dauerhaft
>> reservieren (auf dem Stack), und der Compiler stellt sicher, dass deine
>> Firmware zu jeder Zeit genügend Speicher hat, um fehlerfrei ausgeführt
>> zu werden.
> Da passt was nicht. Stack ist dynamisch und zur Compilerzeit nicht immer
> oder auch überhaupt nicht zu analysieren. Den Compiler kümmert das
> nicht. Du meinst vermutlich das Datensegment?

Ich halte von "Stack", "Heap", "Datensegement" als Bezeichnungen nicht 
viel, wenn es um C geht. Keines dieser drei Dinge ist in C definiert. 
Dort gibt es automatischen, dynamischen und statischen Speicher.

>> Sieht erstmal nach "Speicherverschwendung" aus, der selten genutzte
>> Speicher wird aber benötigt, damit das Programm immer funktioniert.
> Nö. Man Stelle sich vor es gäbe 10 dieser Menüs die aber nur exclusiv
> aktiv sein können. Da ist jede der dynamischen Varianten geeignet um das
> Programm überhaupt zum Laufen zu bekommen

Ja, das ist eben essenziell hier. Die ganze Idee, den Speicher nur 
während der Benutzung des Menüs zu belegen, steht und fällt damit, ob zu 
100% immer absolut sichergestellt ist, dass jegliche andere Benutzung 
dieses Speichers nicht gleichzeitig passieren kann.

von Karl (Gast)


Lesenswert?

Rolf M. schrieb:
> Ich halte von "Stack", "Heap", "Datensegement" als Bezeichnungen nicht
> viel, wenn es um C geht. Keines dieser drei Dinge ist in C definiert.
> Dort gibt es automatischen, dynamischen und statischen Speicher.

Schön. Nenn es wie du willst. Tatsache ist, dass Stack und statisch 
nicht so recht zusammen passen will.

Versucht es doch Mal mit konkreten Argumenten für die eine oder andere 
Variante. Bitte ohne absolutes "Bring deinen Mist in Ordnung", "alles 
doof", "so wird das nie was".

Weitere Tatsache: Der Code des OP läuft. Er möchte aber was dazu lernen. 
Die ewigen Besserwisser und Haaresalter sind nur begrenzt hilfreich.

von Ralf G. (ralg)


Lesenswert?

Walter T. schrieb:
> ich habe eine Funktion callee(), bei der Daten zwischen den Aufrufen
> "gemerkt" werden müssen. Aufgrund der schieren Datenmenge und weil sie
> später nicht mehr benötigt werden, will ich diesen Daten nicht dauerhaft
> Speicherplatz mit static geben oder eine globale Variable daraus machen.

Walter T. schrieb:
> Aber callee() ist eine callback-Funktion, deren Signatur durch
> das aufrufende System bestimmt wird. Wie eine ISR.
Also: Der erste Funktionsrauf knallt irgendwann unverhofft rein, dann 
muss von irgendwoher Speicher organisiert werden. Speicher, der sonst 
auch anderweitig verwendet werden kann. Und der ist zuuufällig beim 
Funktionsaufruf frei??

Walter T. schrieb:
> Peter D. schrieb:
>> Malloc/free bringt auf nem MC nur dann was, wenn sich Funktionen
>> gegenseitig ausschließen, die es benutzen.
>
> Genau. Das ist ja hier der Fall.

Da könnte man vielleicht auch über eine union nachdenken.

von Peter D. (peda)


Lesenswert?

Malloc benötigt, daß man den Bereich des RAM für Stack und für Malloc 
manuell festlegen muß.
Ist der Malloc-Bereich zu klein, dann passen nicht alle Objekte hinein. 
Ist der Stackbereich zu klein, dann läuft er in den Malloc-Bereich und 
zerstört dessen Struktur.
Es kann also passieren, daß ein Bereich zu klein festgelegt wurde, 
obwohl in der Summe noch genügend RAM vorhanden wäre. Jede Art von 
Partitionierung verschlechtert die mögliche Ausnutzung.

von Walter T. (nicolas)


Lesenswert?

Peter D. schrieb:
> Jede Art von
> Partitionierung verschlechtert die mögliche Ausnutzung.

Okay, diese Art von Argument leutet zwar ein - aber ich verstehe es 
nicht. Ich habe irgendwann einmal gelernt, daß bei den Mikrocontrollern 
Stack und Heap aufeinander zu wachsen, und der berüchtigte "Stack 
Overflow" dann eintritt, wenn sie aufeinander treffen. Das würde aber 
bedeuten, dass es egal wäre, welcher von beiden stärker wächst und auch 
kein Partitionierungsproblem auftritt.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Walter T. schrieb:
> Peter D. schrieb:
>> Jede Art von
>> Partitionierung verschlechtert die mögliche Ausnutzung.
>
> Okay, diese Art von Argument leutet zwar ein - aber ich verstehe es
> nicht. Ich habe irgendwann einmal gelernt, daß bei den Mikrocontrollern
> Stack und Heap aufeinander zu wachsen, und der berüchtigte "Stack
> Overflow" dann eintritt, wenn sie aufeinander treffen. Das würde aber
> bedeuten, dass es egal wäre, welcher von beiden stärker wächst und auch
> kein Partitionierungsproblem auftritt.

Jein, der Heap wird durch Fragmentierung nicht optimal genutzt darum 
sollte man an der Stelle schon etwas vorausschauend planen.

von Karl (Gast)


Lesenswert?

Walter T. schrieb:
> Ich habe irgendwann einmal gelernt, daß bei den Mikrocontrollern Stack
> und Heap aufeinander zu wachsen,

Ich auch. Das ist aber, mit Verlaub, ziemlich großer Mist. Wenn auch 
leider an vielen Stellen Stand der Technik.
Ein robustes malloc bekommt einen Speicherbereich zugewiesen, in dem es 
arbeiten darf. Kein Speicher frei, kein erfolgreiches malloc.

Auch der Stack muss nicht in Richtung anderer Daten wachsen.

Ich hatte eben schon ziemlich viel getippt aber mein Handy hat den 
Beitrag verworfen. Bei Interesse führe ich es etwas genauer aus.

von Rolf M. (rmagnus)


Lesenswert?

Karl schrieb:
> Walter T. schrieb:
>> Ich habe irgendwann einmal gelernt, daß bei den Mikrocontrollern Stack
>> und Heap aufeinander zu wachsen,
>
> Ich auch. Das ist aber, mit Verlaub, ziemlich großer Mist. Wenn auch
> leider an vielen Stellen Stand der Technik.

Naja, es maximiert den nutzbaren Speicher.

> Ein robustes malloc bekommt einen Speicherbereich zugewiesen, in dem es
> arbeiten darf. Kein Speicher frei, kein erfolgreiches malloc.
>
> Auch der Stack muss nicht in Richtung anderer Daten wachsen.

Beim AVR zumindest muss er nach unten wachsen. Und wenn er am unteren 
Ende vom RAM angekommen ist, läuft er erst in die I/O-Register, dann in 
die ALU-Register. Das ist nicht wirklich besser, als den Stack ans Ende 
und den Heap davor zu setzen. Und beim Stack ist es sowieso nicht so 
einfach wie bei malloc. Wenn keiner mehr verfügbar ist, kann man nicht 
einfach NULL zurückgeben, sondern das Programm semmelt dann ab - je nach 
Prozessor-Typ unkontrolliert oder durch einen Reset.
Und die Aufteilung, wie viel für beide jeweils reserviert ist, müsste 
man auch für jedes Programm gesondert erstmal ermitteln.

von Karl (Gast)


Lesenswert?

Rolf M. schrieb:
> Naja, es maximiert den nutzbaren Speicher.

Sicher? Es wird so oder so nicht mehr Speicher. Man muss nur nichts 
anpassen um das eine oder andere zu nutzen.

Rolf M. schrieb:
> Beim AVR zumindest muss er nach unten wachsen. Und wenn er am unteren
> Ende vom RAM angekommen ist, läuft er erst in die I/O-Register, dann in
> die ALU-Register. ...
Autsch. Das ist natürlich unglücklich. Da geht's dann nicht.
Cortex M erzeugt per Default einen hardfault. Dort bleibt er bis zum 
watchdog oder Reset. Das ist mir lieber als ein Zombie Programm, das 
später an ganz anderer Stelle abschmiert.

von Kaj (Gast)


Lesenswert?

Karl schrieb:
> Rolf M. schrieb:
>> Naja, es maximiert den nutzbaren Speicher.
>
> Sicher?
Ja. Ueberleg doch mal wie viel Speicher maximal fuer Stack und Heap 
bereitstehen, wenn
- sie aufeinander zuwachsen
- wenn sie voneinander wegwachsen
1
+------------------------+
2
|                        |
3
| Heap ->       <- Stack |
4
|                        |
5
| <------ Memory ------> |
6
|                        |
7
|   <- Heap | Stack ->   |
8
|                        |
9
+------------------------+
Aufeinander zuwachsen ist die sinnvollste Anordnung von Stack und Heap 
um den Speicher maximal nutzen zu koennen.

Karl schrieb:
> Es wird so oder so nicht mehr Speicher.
Der Speicher selbst wird nicht mehr, aber der Speicher kann effizenter 
genutzt werden.

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

Rolf M. schrieb:
...> Beim AVR zumindest muss er nach unten wachsen. Und wenn er am 
unteren
> Ende vom RAM angekommen ist, läuft er erst in die I/O-Register, dann in
> die ALU-Register.
...

grins Da fällt mir ein alter Hack wieder ein: In der Steinzeit der 
AVRs haben wir mal für einen Buffer genau soviel SRAM gebraucht, wie der 
AVR an Bord hatte. In dem Fall war es praktisch, dass man den Stack in 
die Registerbank legen kann...
Unbenutzte IO/Peripherieregister sind auch für einzelne Bits, manchmal 
ganze Bytes, gut...
Dadurch dass der AVR den Stack im RAM-Speicher hat, gibt es plötzlich 
auch die Möglichkeit von dynamisch berechneten Rücksprungadressen. Ein 
echter Fortschritt gegenüber den PICs.

von Peter D. (peda)


Lesenswert?

Marcus H. schrieb:
> grins Da fällt mir ein alter Hack wieder ein: In der Steinzeit der
> AVRs haben wir mal für einen Buffer genau soviel SRAM gebraucht, wie der
> AVR an Bord hatte. In dem Fall war es praktisch, dass man den Stack in
> die Registerbank legen kann...

Welcher AVR soll denn das gewesen sein?
Ich hatte das auch mal probiert bei einem ATTiny25, R0..R15 als 16 Bytes 
Stack zu benutzen. Nur geht das nicht, Push/Pop, Call/Ret gehen nur im 
SRAM-Bereich.

von Marcus H. (Firma: www.harerod.de) (lungfish) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Marcus H. schrieb:
>> grins Da fällt mir ein alter Hack wieder ein: In der Steinzeit der
>> AVRs haben wir mal für einen Buffer genau soviel SRAM gebraucht, wie der
>> AVR an Bord hatte. In dem Fall war es praktisch, dass man den Stack in
>> die Registerbank legen kann...
>
> Welcher AVR soll denn das gewesen sein?
> Ich hatte das auch mal probiert bei einem ATTiny25, R0..R15 als 16 Bytes
> Stack zu benutzen. Nur geht das nicht, Push/Pop, Call/Ret gehen nur im
> SRAM-Bereich.

Aaalt, erster AVR Kern. 2313, 8515, ... die Liga. Als alle Peripherie 
noch direkt an der MCU gehangen ist und nicht, wie bei neueren 
Bausteinen über Trampolin (sprich indirekt), angesprochen werden musste.
Versteh mich nicht falsch - Microchip hat den Bausteinen ein nettes 
Facelift verpasst, so dass man sie Very-Low-Power Controller neben einen 
STM32 hängen kann. Aber die Klarheit aus der Anfangszeit ist weg.

von Karl (Gast)


Lesenswert?

Kaj schrieb:
> Ja. Ueberleg doch mal
Danke fürs Bild, die Frage war aber rethorisch gemeint.
Tatsächlich habe ich viel überlegt und auch schon diverse Probleme damit 
gehabt. Entweder bin ich zu doof oder Ihr ;-) Bitte nicht falsch 
verstehen, aber ich kann einfach keinen echten Vorteil erkennen, wenn 
man Stack und Heap unkontrolliert aufeinander zu wachsen lässt. Das 
wird aber in diversen Implementierungen genau so gemacht und hat auch in 
der Praxis schon viel Mist verursacht.

In dem Moment wo ich zumindest den Heap kontrolliere muss ich mir aber 
schon Gedanken gemacht haben. Dann ist der Weg zu einer IMO besseren 
Variante (entsprechender Controller vorausgesetzt) nicht mehr weit. 
Sobald ein RTOS im Spiel ist, muss man sich meistens Gedanken machen, 
welcher Task/Prozess/Thread wieviel Stack braucht. Das ins Linkerskript 
zu klopfen juckt mich auch nicht mehr.

Kaj schrieb:
> Der Speicher selbst wird nicht mehr, aber der Speicher kann effizenter
> genutzt werden.

Für die "maximale" Nutzung müsste man schon auf's Byte genau wissen 
wieviel Stack und Heap man belegen wird. Viel Spaß dabei, aber nicht 
wundern, wenn es manchmal nicht so läuft wie geplant.

Was meinst Du mit "effizient"?
Woran erkennst Du, dass Dir gerade der Speicher ausgegangen ist?

Meine Meinung habe ich. Zumindest ein valides Argument dafür auch. Was 
sind die Argumente dagegen (und damit pro "Heap -> <- Stack")? Ich habe 
nichts dagegen meinen Horizont zu erweitern.

von Blub B. (googoo)


Lesenswert?

Karl schrieb:
> Meine Meinung habe ich. Zumindest ein valides Argument dafür auch. Was
> sind die Argumente dagegen (und damit pro "Heap -> <- Stack")? Ich habe
> nichts dagegen meinen Horizont zu erweitern.

Na im Grenzfall kann Heap oder eben der Stack den maximalen Speicher 
nutzen, im anderen Szenario kann es sein daß der Heap überläuft obwohl 
der Stack fast leer ist (oder andersrum)

von Blub B. (googoo)


Lesenswert?

In einem der Fälle ist Heap und Stack jeweils maximal 1/2 des Speichers, 
im anderen Fall kann der Speicher dynamisch zwischen Heap und Stack 
aufgeteilt werden.

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.