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.
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.
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.
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):