Avr: Objekte, C++ und Speicherverwaltung

Gast #4436679
Lesenswert?

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 :) !
Gast #4436685
Lesenswert?

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.
Gast #4436690
Lesenswert?

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.
Gast #4436697
Lesenswert?

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?
Gast #4436702
Lesenswert?

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
}
Angehängte Dateien:
Gast #4436712
Lesenswert?

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.
Gast #4436716
Lesenswert?

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 :(.
Gast #4436722
Lesenswert?

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...
Gast #4436728
Lesenswert?

<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.
Gast #4436732
Lesenswert?

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.
Gast #4436933
Lesenswert?

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.
Gast #4437014
Lesenswert?

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.
Gast #4437168
Lesenswert?

>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.
Gast #4437621
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren