RAM überlauf nach einiger Zeit?

OP #3276627
Lesenswert?
• ▲
▼
Hallo,

Führt dieser Code:
1
char* UART_gets()
2
{
3
  uint8_t length = 1;
4
  char* line = malloc(sizeof(char) * length);
5
  memset(line, 0, length);
6
  line[0] = -1;
7
  
8
  while ( 1 )
9
  {
10
    line[length - 1] = UART_getc();
11
    if ( line[length - 1] == '\0')
12
      break;
13
    else
14
    {
15
      length++;
16
      
17
      char* newLine = realloc(line, sizeof(char) * length);
18
      if ( newLine != NULL )
19
        line = newLine;
20
      else
21
        break;
22
      
23
      line[length - 1] = 0;
24
    }
25
  }
26
  
27
  return line;
28
}

zu einem Überlaufen des RAMs nach mehrmaligem Ausführen wenn man nur 256 
bytes hat?

Gruß
Jonas
#3276650
Lesenswert?
• ▲
▼
Die Antwort hast du schon gekriegt.

Ich sags dir noch mit begründung:
>  char* line = malloc(sizeof(char) * length);

Reserviert Speicher, den musst du irgendwann freigeben.

Dieses vorgehen ist auf PCs durchaus üblich, aber auf einem 
Mikrocontroller würde ich den Speicher nicht dynamisch verwalten, 
sondern statisch.

Also du empfängst 16 Bytes, dann verarbeitest du die, dann wider 16 
Bytes empfange etc.

Dann weisst du, du brauchst 16 Bytes, und du brauchst nie mehr, den du 
sowieso nicht hast.

16 Bytes ist als Beispiel anzusehen.



mfg Andreas
#3276664
Lesenswert?
• ▲
▼
Ich kann hier Andreas B. nur zustimmen.
Besonders bei kleinen Controllern ist es bedeutend einfacher und 
effizienter, auf dynamische Arrays zu verzichten.

Irgendwo vergisst du mal ein free() und schon hast du Speicherbereiche, 
die nicht mehr benutzt werden können. Das kann auf einem PC natürlich 
auch passieren, da sind die Auswirkungen aber im Allgemeinen nicht so 
gravierend.
Gast #3278070
Lesenswert?
• ▲
▼
Wenn Du auf einen AVR (od. einen anderen µC) programmierst, dann findest 
Du z.B. in der Codesammlung genug Beispiele, wie man das löst.

Du hast nur eine gewisse Größe vom Speicher zur Verfügung. Dein Code 
berücksichtigt das aber nicht. Iwie. ist es auch seltsam, dass Du immer 
nur 1 Byte zusätzlich allokierst. Verwende halt einen Ringspeicher und 
Interrupts, der bei Empfang eines Zeichens beschrieben wird. Ist dieser 
voll (Überschreitung) bzw. wurde die Null-Termierung erkannt, so wird 
ein Flag gesetzt.

Ringspeicher http://www.mikrocontroller.net/articles/FIFO
UART http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
UART + Ringspeicher Beitrag "AVR-GCC: UART mit FIFO"
Moderator #3278208
Lesenswert?
• ▲
▼
Ganz abgesehen davon, ob du den Speicher statisch oder dynamisch 
reservierst: Der Speicherüberlauf ist garantiert, wenn aus irgendeinem 
Grund (Fehler in der Gegenseite oder Übertragungsfehler) das Endebyte 
('\0') nicht empfangen wird.

In 99% aller Fälle kann die empfangene Nachricht Byte für Byte, ohne 
Zwischenspeicherung der gesamten Nachricht verarbeitet werden. Das 
solltest du dann auch tun. Wenn das nicht geht, musst du den Lesevorgang 
ab einer bestimmten Byteanzahl (die einen Fehlerfall signalisiert) 
abbrechen.
#3280030
Lesenswert?
• ▲
▼
Der empfangene String darf maximal 128 Bytes groß sein. Realloc fordert 
zuerst den neuen Speicher an, kopiert die Daten und gibt erst dann den 
alten frei. Wenn du also bei Zeichen 127 bist, hast du 127 Bytes belegt 
und dann werden zusätzlich die 128 Bytes für das letzte Zeichen 
reserviert. Das führt zu einem Speicherverbrauch von 255 Bytes.

Und dein Program braucht anderweitig sicher auch noch Speicher und schon 
wird es knapp.
OP #3283719
Lesenswert?
• ▲
▼
Hallo,
um nochmal auf das Ram Problem zurückzukommen:
Wenn der Microcontroller einige male etwas über Uart empfangen hat (ca 
50-200) mal stürzt er ab. Dies zeigt sich darin, dass er immer an einem 
bestimmten Punkt sich aufhängt. Ich würde mich sehr darüber freuen wenn 
sich jemand mal meinen Code ansehen könnte und mir vielleicht ein paar 
Probleme nennen könnte. Bedanke mich schon mal im Foraus.
Gruß Jonas
Angehängte Dateien:
Persönliche Seite #3284038
Lesenswert?
• ▲
▼
Seh ich das richtig, das du im RX interrupt blockierend liest?
Damit müllst du dir im blödestem Fall den Stack voll, du sollstest 
wenigstens das Interrupt-Flag löschen, oder noch besser, ohne Interrupt 
in der Main pollen...

Außerdem ist es extrem unschön das deine Funktion keinen Fehlerwert 
zurückliefert wenn es einen Overflow gab.
Auch die Prüfung > 0 ist etwas unsinnig. Du hast ja nun gerade per 
interrupt mitbekommen, das wenigstens ein Zeichen vorliegt.
Persönliche Seite #3284612
Lesenswert?
• ▲
▼
Hier
1
ISR(USART_RX_vect)
2

3
{
4

5
    if ( UART_gets(uart_string, 20) > 0 )
6

7
    {
8

9
      uart_receive_complete = true;
10

11
    }
12

13
}
 rufst du doch die UART_gets Funktion auf, welche wiederum 20x
1
uint8_t UART_getc(void)
2

3
{
4

5
  while (!(UCSRA & (1<<RXC)))   // warten bis Zeichen verfuegbar
6

7
  ;
8

9
  return UDR;                   // Zeichen aus UDR an Aufrufer zurueckgeben
10

11
}
aufruft!

Jonas E. schrieb:
> Das Interrupt-Flag wird doch automatisch gelöscht, wenn ich die Daten
> aus dem UART Register lese?

Das kann sein, solltest du aber im Datenblatt des Prozessor 
verifizieren, trotz allem ist das sehr unschön im Interrupt irgendwelche 
länglichen UART Strings zu empfangen, das ginge in der Hauptschleife 
sehr viel einfacher und stressfreier.

Im blödestem Falle wird nämlich der Interrupt sofort wieder aufgerufen, 
du hast der Hauptschleife aber gerade signalisiert das sie lesen kann 
und bretzelst die Daten im nächstem Moment wieder über...
Gast #3284978
Lesenswert?
• ▲
▼
Jonas E. schrieb:
> Wie kann ich denn mit dieser Vorgehensweise einen String vernünftig
> empfangen?

Man richtet einen Empfangspuffer ein (fest) und hängt immer das neueste 
Zeichen hinten an, bis der String komplett ist - z.B. weil ein CR 
gekommen ist. Dann setzt man ein Flag fürs Hauptprogramm, dass eine neue 
Message vorliegt.

Gruss Reinhard
#3285807
Lesenswert?
• ▲
▼
>Man richtet einen Empfangspuffer ein (fest)

ich würde mal behaupten, man richtet ZWEI ein..

wenn man nämlich nur:
>Dann setzt man ein Flag fürs Hauptprogramm,

macht, hat man ja weiterhin das Problem, dass weiterhin Daten auflaufen, 
während das Hauptprogramm mit den "alten" Daten irgendwas macht..



PS: "PC-Programmierung" ist der falsche Forums-Bereich, oder ???
Gast #3285847
Lesenswert?
• ▲
▼
Robert L. schrieb:
> ich würde mal behaupten, man richtet ZWEI ein..

das kommt halt drauf an, ob weiter Daten kommen können, oder ob der 
Gegner erst mal auf Antwort wartet. Aber erst mal so einfach wie 
möglich, wir wollen Jonas ja nicht gleich ganz verschrecken.

Gruss Reinhard

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