Hallo, ich habe da ein kleines Problem, welches ich nicht ganz nachvollziehen kann. Ich habe eine Klasse für einen Ringspeicher geschrieben, welche 256 Bytes Buffer nutzt (jedes Objekt). Ich nutze den Atxmega16a4. Meine Programmausführung ist davon abhängig, wie groß ich diesen Buffer anlege und kommt ggf. ganz zum stehen. Selbst wenn ich 10 dieser Ringspeicher anlege und über eine Inputvariable diese Ringspeicher beschreibe, legt der Compiler nur ein paar Bytes im Speicher an. Es müssten doch deutlich mehr sein, soviele Register gibt es doch nicht, dass diese 2560 Bytes kommplett in diesen gehalten werden. Es scheint dann eine magische Grenze zu geben, ab wo das Programm wieder reibungslos läuft. Wieso wird so wenig Speicher angelegt, obwohl es 2560 Bytes sein sollten? Übersehe ich eine Projekteinstellung? Danke schonmal :) !
Jörg schrieb: > Es scheint dann eine magische Grenze zu geben, ab wo das Programm > wieder reibungslos läuft. Wieso wird so wenig Speicher angelegt, obwohl > es 2560 Bytes sein sollten? kannst du uns auch etwas code zeigen? Wenn der speicher mit New/Malloc angelegt wird, wirst du es nicht sehen.
Mein Tipp: Verzichte auf die dynamische Speicherverwaltung. Lege diese Objekte statisch an. Von mir aus global in einem Array. Dann zeigt dir der Compiler den korrekten Verbrauch und die Gefahr von Heap/Stack Kollisionen sinkt erheblich.
Der Compiler belegt nur Platz für statische Variablen. Objekte werden hingegen in der Regel dynamisch (mit new) angelegt (was nicht heissen soll, dass es keine statischen Objekte gibt). Wenn deine Objekte zur Laufzeit vom Code erzeugt werden, dann kannst du am Output des Compilers nicht mehr ablesen, wieviel RAM das Programm wirklich benötigt. War Dir das soweit klar?
Klar mach ich. Natürlich sind alle Objekte bereits statisch angelegt - sofern ich den Begriff hier richtig verstanden habe. Kein new, delete oder malloc. Avr Studio 7.
1 | #include <avr/io.h> |
2 | #include "c_ringbuffer.h" |
3 | #include "c_avr_iopin.h" |
4 | |
5 | int main(void) |
6 | {
|
7 | c_ringbuffer ringe[12]; |
8 | c_avr_iopin led(&PORTD, PIN7_bm, true, false); |
9 | int i; |
10 | |
11 | while (1) |
12 | {
|
13 | led.toggle(); |
14 | |
15 | for(i = 0; i < 12; i++) |
16 | ringe[12].addItem(i); |
17 | }
|
18 | }
|
Ulrich F. schrieb: > Lege diese Objekte statisch an. Von mir aus global in einem Array. Naja, globale Objekte sind aus softwaretechnischer Sicht eher hässlich.
Jörg schrieb: >
1 | > for(i = 0; i < 12; i++) |
2 | > ringe[12].addItem(i); |
3 | >
|
Du schreibst hier über die Grenze eines Arrays hinaus. Kein Wunder dass da was schiefläuft.
Mark B. schrieb: > Jörg schrieb: >>> for(i = 0; i < 12; i++) >> ringe[12].addItem(i); >> > Du schreibst hier über die Grenze eines Arrays hinaus. Kein Wunder dass > da was schiefläuft. Ich habe den Code kurz reduziert und zusammengestellt, damit ich das hier veranschaulichen kann. Tatsächlich ein Fehler, aber das behebt das Problem nicht.
Mark B. schrieb: > Ulrich F. schrieb: >> Lege diese Objekte statisch an. Von mir aus global in einem Array. > > Naja, globale Objekte sind aus softwaretechnischer Sicht eher hässlich. In meinem gezeigten Beispiel kommt die led bereits zum stehen aber 3 Bytes im Ringspeicher :(.
Mark B. schrieb: > Naja, globale Objekte sind aus softwaretechnischer Sicht eher hässlich. Zu 100% richtig! Aber so werden sie vom Compiler gesehen und der Verbrauch richtig angezeigt. Wenigstens testweise kann man das ja mal tun... Jörg schrieb: > int main(void) > { > c_ringbuffer ringe[12]; So werden die Objekte auf dem Stack angelegt, und der Verbrauch ist nicht zu sehen. 3,3K Ram minus 12 mal 256Byte Buffer ( plus Wasserkopf) Da bleibt nicht mehr viel...
<code> int main(void) { c_ringbuffer ringe[12]; } </code> Ich bin da jetzt nicht 100% sicher, aber immerhin 90%. Und zwar meine ich, dass die Variable c_ringbuffer hier auch erst zur Lautzeit angelegt wird, allerdings auf dem Stack. Denn es handelt sich um eine lokale Variable innerhalb der main Funktion. Versuche mal, sie global außerhalb der main Funktion zu verschieben oder schreibe "static" davor.
Stefan U. schrieb: > <code> > int main(void) > { > c_ringbuffer ringe[12]; > } > </code> > > Ich bin da jetzt nicht 100% sicher, aber immerhin 90%. Und zwar meine > ich, dass die Variable c_ringbuffer hier auch erst zur Lautzeit angelegt > wird, allerdings auf dem Stack. Denn es handelt sich um eine lokale > Variable innerhalb der main Funktion. > > Versuche mal, sie global außerhalb der main Funktion zu verschieben oder > schreibe "static" davor. Tatsächlich, also globale Objekte zeigt mir dieser nun 99,9% an, wie erwartet.
Hallo Jörg, irgend wer hat hier im Forum mal diese Funktion zur Anzeige des freien Ramspeichers vorgeschlagen:
1 | #ifdef ARDUINO_UNO
|
2 | int freeRam() { |
3 | extern int __heap_start, *__brkval; |
4 | int v; |
5 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); |
6 | }
|
7 | #endif
|
Mit der Funktion kannst Du zur Laufzeit sehen, wie viel HEAP noch übrig ist und wie viel für weitere Objekte verbleibt. Ich benutze sie zum zyklischen Speichercheck.
Der Haken an dieser Methode ist, dass der Heap fragmentiert werden kann. Solange man sich nicht außerordentlich darum bemüht, dies zu verhindern, wird das auch der Fall sein. Dann stellt sich die Frage: Was ist freier Speicher? a) Der größe verfügbare zusämmenhängende Block, oder b) Alle freien Blöcke zusammen gezählt? Genau genommen muss man für jeden einzelnen Bedarfsfall (also jede einzelne Funktion, Methode und jeden Aufruf von new, malloc, calloc sowie die Library Funktionen, die Heap benötigen, wie z.B. printf) prüfen, ob noch genügen freier Speicher vorhanden ist.
Cpp schrieb: > Mit der Funktion kannst Du zur Laufzeit sehen, wie viel HEAP noch übrig > ist Ein wirklicher Schutz vor Stack/Heap Kollisionen ist das auch nicht.
>Genau genommen muss man für jeden einzelnen Bedarfsfall (also jede >einzelne Funktion, Methode und jeden Aufruf von new, malloc, calloc >sowie die Library Funktionen, die Heap benötigen, wie z.B. printf) >prüfen, ob noch genügen freier Speicher vorhanden ist. So mache ich es quasi für mein Debugging: Ich gebe den Heap vor und nach der Initialisierung aus, damit ich abschätzen kann, wie lange es noch reichen wird. Bei meinem Programm sollten 100Byte Reserve reichen.
Ich hatte bisher nur eine Einzige Anwendung, wo der Speicher knapp wurde. Da habe ich dafür gesorgt, dass auf Knopfdruck eine Wiederholschleife gestartet wird, die den freien Speicher testet. Etwa so (pseudo code):
1 | int size=4096; |
2 | while (1) |
3 | { |
4 | if (kann size byte allokieren) |
5 | { |
6 | den gerade allokierten Speicher wieder freigeben; |
7 | printf("Größer freier Speicherblock = %d bytes",size); |
8 | break; |
9 | } |
10 | else |
11 | { |
12 | if (size<100) |
13 | { |
14 | printf("Speicher ist voll!"); |
15 | break; |
16 | } |
17 | size -= (size/8); |
18 | } |
19 | } |
100 Bytes brauche ich mindestens, sonst stürzt das Programm ab. Diesen Grenzwert habe ich experimentiell herausgefunden.
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.