Gibt es einen Nachteil bei der Zuweisung einer großen Menge des Stapels für ein einzelnes Array in einem eingebetteten System?

12

Normalerweise habe ich kein Problem damit, zu entscheiden, ob einige Daten global, statisch oder auf dem Stack sein müssen (hier keine dynamische Zuordnung, daher keine Verwendung des Heapspeichers). Ich habe auch ein paar Fragen / Antworten wie diese gelesen, aber meine Frage ist spezifischer, da sie im Vergleich zum Systemspeicher eine große Datenmenge enthält.

Ich arbeite an einem vorhandenen Code, den ich zu verbessern versuche (Design, mögliche Probleme, Leistung usw.). Dieser Code läuft auf einer alten 8-Bit-MCU mit nur 4 KB RAM . In diesem Code stelle ich die Verwendung eines Arrays von fast 1 KB (ja, 1 KB auf einem 4-KB-RAM- System). Jedes Byte dieses Arrays wird verwendet, das ist nicht die Frage. Das Problem ist, dass dieses Array ein statisches Array in der Datei ist, in der es deklariert ist, sodass sein Lebenszyklus mit dem des Programms identisch ist (dh als unendlich angesehen werden kann).

Nachdem ich den Code gelesen hatte, stellte ich jedoch fest, dass dieses Array keinen unendlichen Lebenszyklus benötigt, sondern vollständig prozedural aufgebaut und behandelt wird. Daher sollten wir es nur in der Funktion deklarieren können, in der es verwendet wird. auf diese Weise wäre es auf dem Stapel, und wir würden daher diese 1 KB RAM sparen.

Nun die Frage: Wäre das eine gute Idee? Aus Sicht des Designs gehört es zum Stack, wenn es keinen unendlichen / globalen Lebenszyklus benötigt. Aber hey, das ist 1 KB von 4 KB, gibt es keinen Nachteil , wenn 25% des Arbeitsspeichers so zugewiesen werden ? (das könnten 50% oder mehr des Stapels sein)

Könnte jemand Erfahrungen mit dieser Art von Situation teilen, oder könnte jemand über einen gültigen Grund nachdenken, dieses Array nicht auf den Stapel zu legen? Ich suche technische Nachteile sowie Kommentare zum Design.

Mir ist nur bewusst, dass ich beim Aufrufen dieser Funktion sicherstellen muss, dass tatsächlich 1 KB Stack frei sind. Vielleicht ist das alles, worauf ich aufpassen muss, vielleicht auch nicht.

Tim
quelle
4
Sie haben geschrieben, "und daher diese 1 KB RAM sparen". Speichern Sie es für was? Diese 1 KB müssen verfügbar sein, wenn Sie sie für das Array benötigen. Warum also nicht eine statische Zuordnung vornehmen? Haben Sie eine andere Verwendung für den Speicher, wenn er für das Array nicht benötigt wird?
kkrambo
@kkrambo Irgendwann halten wir ein System für voll, wenn wir nichts mehr zum RAM hinzufügen können, egal ob es sich um etwas Statisches oder um etwas auf dem Stack handelt. Wenn wir dieses Array nur dann auf den Stapel legen, wenn wir es verwenden, würde es Platz für eine andere Funktionalität schaffen, solange sie nicht gleichzeitig verwendet werden. Aber die Frage ist absolut berechtigt, im Moment, wenn wir nichts in der SW ändern, brauchen wir nicht mehr RAM;)
Tim
1
Können Sie klären, ob dieses Array immer denselben Inhalt hat oder ob er sich ändert, wenn die Funktion, die es verwendet, aufgerufen wird?
Blrfl
@Blrfl Ändert sich bei jedem Aufruf der Funktion.
Tim

Antworten:

8

Mir ist nur bewusst, dass ich beim Aufrufen dieser Funktion sicherstellen muss, dass tatsächlich 1 KB Stack frei sind.

Ja, und das ist eine starke Einschränkung. Sie sind statisch sicherer, als einen so großen verfügbaren Speicherplatz auf dem Stapel zu haben. Wenn der Code klein ist und Sie ein aktuelles GCC zum Kompilieren Ihres Codes verwenden, lesen Sie dies .

Übrigens könnten einige billige Mikroprozessoren einen "großen" Anrufrahmen teurer als einen "normalen" verwenden (z. B. weil ihr Befehlssatz einen 1-Byte-Versatz vom Stapelzeiger begünstigen würde). YMMV.

Wenn Sie in C codieren und der Meinung sind, dass der Speicherplatz Ihres großen Arrays für andere Zwecke wiederverwendet werden kann, sollten Sie ihn möglicherweise zu einem Gewerkschaftsmitglied (mit einer globalen Variablen vom unionTyp) machen. Ja, das ist ziemlich hässlich.

Alternativ können Sie einen für Ihre Anwendung geeigneten primitiven Heap-Allokator (und eine andere API als malloc& free....) codieren .

Basile Starynkevitch
quelle
1
Vielen Dank, ich habe tatsächlich ein bisschen mit dieser Art von Antwort gerechnet, dh, ich halte sie statisch zugewiesen, um sicherzugehen, dass es nicht zu einem Stapelüberlauf kommt. Leider habe ich keinen aktuellen GCC-Compiler und der Code ist nicht klein.
Tim
Können Sie nicht (möglicherweise durch Kompilieren von GCC aus dem Quellcode) einen GCC-Compiler für Ihre Plattform erhalten?
Basile Starynkevitch
2
Ich habe schon eins, es ist einfach sehr alt. An einem neuen zu arbeiten, ist weder in meinem Rahmen noch würde es in meinen Zeitplan passen. Aber sicher, einige Dinge wären mit aktuellen Tools einfacher.
Tim
3
Es lohnt sich meiner Meinung nach, Ihren Chef zu bitten, Ihnen einen neueren GCC zu besorgen (entweder indem er Ihnen aktuelle Binärwerkzeuge zur Verfügung stellt oder indem er Ihnen Zeit für die Neukompilierung von GCC lässt), da ein neuerer GCC wahrscheinlich etwas besser optimieren würde (wissen Sie das gcc -flto -Os? ) und Sie könnten etwas Gedächtnis gewinnen ....
Basile Starynkevitch
2
Es ist auf dem richtigen Weg, aber das wird nicht vor einer Weile kommen. Ich habe -Os bereits auf anderen Systemen mit neueren Toolchains verwendet, aber mir war dieser -flto-Parameter nicht bekannt, danke, dass ich darauf hingewiesen habe. (Beachten Sie, dass ich vor einigen Wochen einige Tests mit GCC -Os und -O1-3-Parametern mit GCC 5.4.1 durchgeführt habe und der Arbeitsspeicher die ganze Zeit gleich war. Die FLASH- und die MCU-Laufzeit waren jedoch unterschiedlich. Das war nicht auf der gleichen MCU wie die, die ich in diesem Q / A erwähnte
Tim
6

Bei einem großen Stack ist man eher vorsichtig, da er im RAM rückwärts wächst und Variablenwerte überschreibt, was zu unerklärlichem Verhalten führt. Es wird noch schlimmer, weil Sie die niedrigstmögliche Stapelzeigeradresse kennen und die zuzuweisende Größe subtrahieren müssen, wenn Sie in die Routine eintreten.

Dies ist alles eine Aufgabe für die Hardwarespeicherverwaltung (sollte Traps oder Fehler erzeugen, wenn ein Stapelüberlauf auftritt) oder für den Compiler, da dieser über Funktionen für diese Art der Analyse verfügt.

Ansonsten können Sie mit Ihrem RAM machen, was Sie wollen.

Martin Sugioarto
quelle
4

Wie bereits in früheren Antworten erwähnt, würde ich auch empfehlen, das Array zunächst statisch zu lassen, wenn es in den Arbeitsspeicher passt. In den meisten Fällen ist es sehr viel wichtiger, einen deterministischen Speicherbedarf zu haben, selbst wenn dies bedeutet, dass Sie Speicher für Variablen "verschwenden", die nicht ständig verwendet werden. Wenn Sie große Arrays auf Ihren Stapel legen, wird er viel zu schnell ausgeblasen, und Stapelüberläufe können zu schwer zu findenden und schwer zu reproduzierenden Problemen führen (wenn Sie den Stapel nicht mit MMU schützen können).

Der Vorschlag, den Block mit einigen anderen Daten mit union zu teilen, ist IMO-gültig. Er kann jedoch auch zu schwer zu findenden Problemen führen, wenn Sie darin falsche Variablen finden.

Wenn Ihnen der Speicher ausgeht und Sie dringend kürzer lebende Variablen erstellen müssen, um ihn gemeinsam zu nutzen, bevor Sie das Array in den Stapel verschieben, würde ich eine dynamische Speicherzuweisung in Betracht ziehen, auch wenn dies seine eigenen Nachteile hat. In diesem Fall ist dies möglicherweise keine Antwort, da das Array im Vergleich zum verfügbaren Speicher ziemlich groß klingt.

MaKo
quelle
1

Sie haben eine weitere Option, wenn Sie über einen Flash-Speicher verfügen. Sie können die Zugriffsgeschwindigkeit für den RAM ausgleichen, indem Sie Ihre Daten in Flash speichern und dort lesen und suchen. Sie müssten jeweils nur einen Datensatz in den RAM laden. Es wird etwas komplizierter, wenn Sie die Datensätze aktualisieren müssen. Sie benötigen einen segmentierten, verschleißarmen Mechanismus. Ich habe dies in der Vergangenheit getan und einen Index eingefügt, um den Zugriff zu beschleunigen.

Tereus Scott
quelle
1
Ich habe dies auch in der Vergangenheit getan, aber meine Frage bezog sich eher auf die Probleme, denen ich begegnen könnte, wenn ich dies auf den Stapel lege, und nicht wirklich auf die Alternativen zum RAM, wenn es knapp wird. Trotzdem danke, dass du geantwortet hast
Tim,
1

Insbesondere bei der Arbeit mit eingebetteten Systemen möchten Sie, dass möglichst viele Fehler während der Kompilierung auftreten und zur Laufzeit nichts ausfällt (schön, wenn wir dies erreichen könnten ...).

Wenn Sie große Arrays erstellen, die Sie möglicherweise in einem beliebigen Status Ihres Programms benötigen, der statisch zugewiesen ist, ist dies genau das. Der Linker warnt Sie schließlich, dass dies nicht in den Arbeitsspeicher passt überläuft.

Tofro
quelle