Ich würde gerne wissen, wie viel RAM ich in meinem Projekt verwende, soweit ich das beurteilen kann. Ich habe eine Phase in einem ziemlich großen Projekt erreicht, in der ich festgestellt habe, dass mir der Arbeitsspeicher ausgeht.
Ich habe dies festgestellt, weil ich einen Abschnitt hinzufügen kann und dann irgendwo anders in meinem Code die Hölle losbricht, ohne dass es einen offensichtlichen Grund gibt. Wenn ich #ifndef
was anderes raus habe, klappt es wieder. An dem neuen Code ist programmgesteuert nichts auszusetzen.
Ich vermutete für eine Weile, dass ich das Ende des verfügbaren Arbeitsspeichers erreichte. Ich glaube nicht, dass ich zu viel Stack verwende (obwohl dies möglich ist). Wie kann ich am besten feststellen, wie viel RAM ich tatsächlich verwende?
Beim Durcharbeiten und Ausarbeiten habe ich Probleme, wenn ich an Aufzählungen und Strukturen komme. Wie viel Speicher kosten sie?
zuerst bearbeiten: Auch ich habe meine Skizze so viel geändert seit dem Start, das sind nicht die tatsächlichen Ergebnisse , die ich am Anfang bekam, aber sie sind das, was ich jetzt bekommen.
text data bss dec hex filename
17554 844 449 18847 499f HA15_20140317w.cpp.elf
16316 694 409 17419 440b HA15_20140317w.cpp.elf
17346 790 426 18562 4882 HA15_20140317w.cpp.elf
Die erste Zeile (mit Text 17554) funktionierte nicht, nach langem Bearbeiten funktioniert die zweite Zeile (mit Text 16316) ordnungsgemäß.
Bearbeiten: In der dritten Zeile funktioniert alles, serielles Lesen, meine neuen Funktionen usw. Ich habe im Wesentlichen einige globale Variablen und doppelten Code entfernt. Ich erwähne dies, weil es (wie vermutet) nicht um diesen Code per sae geht, sondern um die RAM-Auslastung. Das bringt mich zurück zu der ursprünglichen Frage, wie man es am besten misst. Ich überprüfe immer noch einige Antworten, danke.
Wie interpretiere ich die obigen Informationen tatsächlich?
Bisher ist mein Verständnis:
`TEXT` is program instruction memory
`DATA` is variables (unitialised?) in program memory
`BSS` is variables occupying RAM
Warum funktioniert das zweite, das erste jedoch nicht? Wenn es DATA+BSS
dann ist, besetzen beide mehr als 1024.
Erneut bearbeiten: Ich habe die Frage bearbeitet, um den Code einzuschließen, aber jetzt habe ich sie entfernt, da sie wirklich nichts mit dem Problem zu tun hatte (abgesehen von möglicherweise schlechten Codierungspraktiken, Variablendeklarationen und dergleichen). Sie können den Code überprüfen, indem Sie sich die Änderungen noch einmal ansehen, wenn Sie ihn wirklich sehen möchten. Ich wollte noch einmal auf die Frage zurückkommen, die sich eher mit der Messung der RAM-Auslastung befasst.
String
Typ in Ihren Programmen? Dies führt bekanntermaßen zu häufigen dynamischen Speicherzuweisungen und -freigaben, wodurch der Heap möglicherweise so fragmentiert wird, dass möglicherweise kein Speicher mehr vorhanden ist.String
wegen des Overheads von s fern . Ich arbeite gerne mit char-Arrays, das heißt, ich definiere fast immer alle char-Arrays mit einer festen Größe (im Moment habe ich EIN Byte-Array, das nicht nur darauf beruht, dass ich die Inhaltslänge für verschiedene Neukompilierungen ändere.Antworten:
Sie können die Funktionen von AVRGCC: Monitoring Stack Usage verwenden
Die Funktion sollte die Stack-Auslastung überprüfen, meldet jedoch, dass der tatsächliche RAM-Speicher (während der Ausführung) noch nie verwendet wurde. Dies geschieht, indem der RAM mit einem bekannten Wert (0xC5) "gemalt" (gefüllt) wird und dann der RAM-Bereich überprüft wird, der zählt, wie viele Bytes noch den gleichen Anfangswert haben.
In dem Bericht wird der nicht verwendete Arbeitsspeicher angezeigt (minimaler freier Arbeitsspeicher). Daher können Sie den maximal verwendeten Arbeitsspeicher berechnen (Gesamter Arbeitsspeicher - gemeldeter Arbeitsspeicher).
Es gibt zwei Funktionen:
StackPaint wird während der Initialisierung automatisch ausgeführt und "malt" den RAM mit dem Wert 0xC5 (kann bei Bedarf geändert werden).
StackCount kann jederzeit aufgerufen werden, um den nicht verwendeten RAM zu zählen.
Hier ist ein Anwendungsbeispiel. Macht nicht viel, soll aber zeigen, wie man die Funktionen benutzt.
quelle
Die Hauptprobleme, die Sie mit der Speichernutzung zur Laufzeit haben können, sind:
malloc
odernew
)Beide sind tatsächlich identisch mit dem AVR SRAM (2K auf Arduino), der für beide verwendet wird (zusätzlich zu statischen Daten, deren Größe sich während der Programmausführung nie ändert).
Im Allgemeinen wird die dynamische Speicherzuweisung auf MCUs selten verwendet. In der Regel wird sie nur von wenigen Bibliotheken verwendet (eine davon ist
String
class, von der Sie sagten, dass Sie sie nicht verwenden, und das ist ein guter Punkt).Der Stapel und der Haufen sind im Bild unten zu sehen (mit freundlicher Genehmigung von Adafruit ):
Das am meisten erwartete Problem ist daher der Stapelüberlauf (dh, wenn der Stapel in Richtung des Heaps wächst und überläuft), und wenn der Heap nicht bei allen Überläufen in der statischen Datenzone des SRAM verwendet wurde. Sie haben ein hohes Risiko für:
Um zu wissen, wie viel Speicher zwischen der Oberseite des Heapspeichers und der Oberseite des Stapels verbleibt (wir können es auch die Unterseite nennen, wenn wir sowohl den Heapspeicher als auch den Stapel auf demselben Bild darstellen, wie unten dargestellt) kann die folgende Funktion verwenden:
In dem obigen Code,
__brkval
weist auf die Spitze des Haufens ist aber ,0
wenn der Haufen nicht verwendet worden ist, wobei in diesem Fall verwenden wir&__heap_start
die Punkte__heap_start
, die erste Variable , dass markiert den Boden des Haufens;&v
zeigt natürlich oben auf den Stapel (dies ist die letzte Variable, die auf den Stapel verschoben wurde), daher gibt die obige Formel die Menge an Speicher zurück, die für den Stapel (oder den Heap, wenn Sie ihn verwenden) zur Vergrößerung verfügbar ist.Sie können diese Funktion an verschiedenen Stellen Ihres Codes verwenden, um herauszufinden, wo sich diese Größe dramatisch verringert.
Wenn diese Funktion jemals eine negative Zahl zurückgibt, ist es natürlich zu spät: Sie haben den Stapel bereits überschritten!
quelle
malloc
undnew
der einzige Weg, wie ich das tun kann? Wenn ja, dann habe ich nichts dynamisches. Außerdem habe ich gerade erfahren, dass die UNO 2K SRAM hat. Ich dachte es wäre 1K. Unter Berücksichtigung dieser Faktoren geht mir nicht der Arbeitsspeicher aus! Ich muss woanders suchen.calloc
. Möglicherweise verwenden Sie jedoch Bibliotheken von Drittanbietern, die die dynamische Zuordnung verwenden, ohne dass Sie dies wissen (Sie müssten den Quellcode aller Abhängigkeiten überprüfen, um sicherzugehen)Wenn Sie herausfinden, wie Sie die generierte .elf-Datei in Ihrem temporären Verzeichnis finden, können Sie den folgenden Befehl ausführen, um eine SRAM-Verwendung zu sichern, bei
project.elf
der diese durch die generierte.elf
Datei ersetzt werden soll. Der Vorteil dieser Ausgabe ist die Fähigkeit , zu überprüfen , wie Ihr SRAM verwendet wird. Müssen alle Variablen global sein, sind sie wirklich alle erforderlich?Beachten Sie, dass dies keine Verwendung des Stacks oder des dynamischen Speichers anzeigt, wie Ignacio Vazquez-Abrams in den Kommentaren unten angegeben.
Zusätzlich
avr-objdump -S -j .data project.elf
kann ein geprüft werden, aber keines meiner Programme gibt etwas damit aus, so dass ich nicht sicher bin, ob es nützlich ist. Es sollte 'initialisierte (nicht null) Daten' auflisten.quelle
avr-size
. Das zeigt Ihnen jedoch keine dynamischen Zuordnungen oder Stapelverwendung.avr-objdump
und experimentiert undavr-size
werde meinen Beitrag in Kürze bearbeiten. Danke dafür.Es ist am besten, eine Kombination aus manueller Schätzung und Verwendung des
sizeof
Operators zu verwenden. Wenn alle Ihre Angaben statisch sind, sollte dies ein genaues Bild ergeben.Wenn Sie dynamische Zuordnungen verwenden, tritt möglicherweise ein Problem auf, sobald Sie mit der Freigabe des Speichers beginnen. Dies liegt an der Speicherfragmentierung auf dem Heap.
Eine Aufzählung nimmt so viel Platz ein wie eine
int
. Wenn Sie also einen Satz von 10 Elementen in einerenum
Deklaration haben, wäre dies der Fall10*sizeof(int)
. Außerdem ist jede Variable, die eine Aufzählung verwendet, einfach eineint
.Für Strukturen wäre es am einfachsten
sizeof
, dies herauszufinden. Strukturen nehmen einen (minimalen) Raum ein, der der Summe ihrer Mitglieder entspricht. Wenn der Compiler eine Strukturausrichtung durchführt, kann dies mehr sein, was jedoch im Fall von unwahrscheinlich istavr-gcc
.quelle
sizeof
für diesen Zweck zu verwenden. Im Moment habe ich schon fast 400 Bytes (global) abgerechnet. Jetzt gehe ich durch und berechne die Aufzählungen (manuell) und die Strukturen (von denen ich einige habe - und ich werde sie verwendensizeof
) und erstatte Bericht.sizeof
die Größe Ihrer statischen Daten wirklich kennen müssen , da diese von avrdude IIRC gedruckt werden.Es gibt ein Programm namens Arduino Builder , das eine übersichtliche Visualisierung der Menge an Flash, SRAM und EEPROM bietet, die Ihr Programm verwendet.
Der Arduino Builder ist Teil der CodeBlocks Arduino IDE- Lösung. Es kann entweder als eigenständiges Programm oder über die CodeBlocks Arduino IDE verwendet werden.
Leider ist Arduino Builder ein bisschen alt, aber es sollte für die meisten Programme und die meisten Arduinos, wie das Uno, funktionieren.
quelle