Arduino MEGA2560 Speicherüberlauf? Mit 18% Sketch und 30% Memory??

Hallo,

ich hab seit Stunden oder bzw. Tagen das Problem in meinem aktuellen Projekt das ich in min destens einer Variable merkwürdige Zeichen in meiner Funktion "Webinterface" enthalten habe wie z.B "styles1.css QNÍFileName" was eigentlich "styles1.css FileName" bedeuten soll (is ein char*).

Kurzer Hintergrund: Ich habe mehrere eigenständige Funktion, in der ich String`s deklariert habe (ja ich verwende Strings, aber auch nur da wo es sonst extrem umständlich wäre). Dies funktioniert alles Super, mein Webinterface arbeitet mit der o.g. Variable mit den richtigen Inhalten. Somit alles fein!

Jetzt habe ich eine weitere Funktion Bsp. "neue Funktion", in der ebenfalls wie oben beschreiben 2 lokale Strings deklariert und verwendet werden. Diese Funktion enthält keine Variablen mit den gleichen namen anderer sowie werden keine globale Variablen, die mit "Webinterface" irgendwie in Verbindung stehen.

Wenn ich diese Funktion nicht verwende geht das Webinterface einwandfrei. Ist die Funktion irgendwo implementiert, kommt es zu den o.g. merkwürdigen Zeichen, obwohl die Funktion aufgrund z.B. einer IF bedingung definitiv nicht durchlaufen wird. KOmmentier ich den AUfruf wieder aus, ist alles wieder OK.
Innerhalb der Funktion, kann auch keine fixe Codingzeile ausgemacht werden. Mit auskommentieren ist es mal die, mal die etc.

Ich bin selbst Programmierer bereits seit 10 Jahren, allerdings erst seit 2 Jahren mit dem Arduino.
Ich kanns mir net Erklären.

Jetzt vielleicht das wichtigste, mein Sketch beträgt 18%, und Memory Usage 30%.
Selbst eine FreeMemory Ausgabe gab mir immer ein Wert von 5000 zurück.

?!? Hat hier jemand eine Idee?

Jetzt vielleicht das wichtigste, mein Sketch beträgt 18%, und Memory Usage 30%.
Selbst eine FreeMemory Ausgabe gab mir immer ein Wert von 5000 zurück.

Das hat auch nichts mit einem Speicherüberlauf zu tun. Eher hast du dein Array/String falsch deklariert. Ohne Sketch wird dir da aber keiner weiterhelfe können.

Jupp oder addierst eine Variable hoch und vergisst diese zurückzusetzen..

umso höher sie zählt umso mehr wird anderes im Ram überschrieben..

Hatte das mal mit nem Timer.. ohne Delays ist der nach 2 Sekunden in den reset gegangen, da hab ich das dann erst bemerkt.

Las doch mal im Betrieb den freien RAM ausgeben

Diesen Effekt "Wenig RAM-Verbrauch + wenig Flash-Verbrauch = dennoch seltsame Zeichen" hatte ich in meinem kürzlich vorgestellten Projekt SudokuSolver UNO ebenfalls. Viel Lesen und einiges Experimentieren brachten mir die Erkenntnis, dass die eingesetzte String-Class bei Aufruf einzelner (augenscheinlich notwendiger) Strings dennoch Dinge ins RAM schreibt, die man nicht kontrollieren kann. Das bestätigen auch diverse Aussagen vieler echter Experten hier im Forum.

Nach vielen teilweise recht frustrierender Versuche habe ich mir dann tatsächlich die Mühe gemacht, jeden - aber auch wirklich JEDEN "String" in ein Char*-Array umzuwandeln und NUR NOCH mit den vielen C++ - Funktionen zu behanden. Für einige wenige mir aus PHP bekannten Funktionen habe ich Ersetzungen in C++ nachgebaut - so dass ich auf dann Biegen und Brechen absolut NULL "String"-Object nutzen musste. Es war mühsam und anstrengend. Zugegeben. Aber der Effekt davon war, dass diese o.g. "Seltsamen Zeichen" im Display nun vollkommen verschwunden waren und das Progamm absolut stabil läuft. Sogar mit Rekursionen. Und genau in diesem Zusammenhang habe ich auch die hier im "Playground" vorgestellte Auslesung des freien RAMs einsetzen können und hatte somit den Überblick über nahezu jedes Byte im 328p.

Ich kann echt nur dringends empfehlen, für weitere "Freude" bei der Arbeit mit dem Arduino auf jegliche Verwendung der String-Class zu verzichten. Auch wenn es evtl. mühsam sein sollte - der spätere Erfolg belohnt einen hinterher um so mehr.

Nachsatz*

Ich muss zu meiner Schande gestehen ... dass das nicht "das Einzige" war, was mir den Erfolg brachte. Denn es gab dann noch diverse Classes, die ebenfalls irgendwie nicht zu kontrollierende Ergebnisse brachten. Zum Beispiel das "print" in "LiquidCrystal" oder auch "Serial...". Somit bin ich hingegangen, und habe für das Sudoku-Projekt auch diese Classes neu erstellt und auf ein Minimum reduziert. Außerdem bin ich hingegangen und habe konsequent jede einzelne feste Zeichenkette ins PROGMEM ausgelagert. Erst danach hatte ich den nahezu vollständigen Überblick und konnte den "Solver" sogar noch um einen "Generator" ergänzen. Alles zusammen läuft in einem einzelnen 328p und ich habe immer noch genügend Platz für andere "Spielereien".

Und zeig uns mal den Sketch.
Grüße Uwe

RudiDL5:
dass die eingesetzte String-Class bei Aufruf einzelner (augenscheinlich notwendiger) Strings dennoch Dinge ins RAM schreibt, die man nicht kontrollieren kann.

Das passiert fast ständig, da dauernd neue Objekte angelegt und zerstört werden. Schon bei so einfachen Dingen wie Strings konkatenieren. Anfänger denken die String Klasse ist einfach. Aber das ist sie nur in der Verwendung. Was da im Hintergrund abläuft ist oft der reinste Horror. Und dann fehlen Anfängern die Kenntnisse das zu minimieren (auch eben weil sie gar nicht erst verstehen was sie eigentlich tun). z.B. am Anfang mal mit reserve() Speicher reversieren damit nicht ständig neuer Speicher angelegt wird. Oder dass man String Objekte immer als Referenz an eine Funktion übergeben muss - oder es wird eine Kopie erstellt.

Dazu kommt es eben das Problem dass dynamischer Speicher halt nicht in der IDE angezeigt wird. Was da eigentlich angezeigt ist trotz des Namens der statische Speicher. Dynamischer Speicher steht erst zur Laufzeit fest. Den kann die IDE nicht kennen.

Wobei auf dem Mega 70% frei eigentlich ein riesiger Puffer ist, so dass man sich auch mal erlauben kann ineffizient zu programmieren. Da gibt es aber noch genug andere Fehlerquellen.

Seufz Der Begriff "Horror" ist wohl der treffendste den man bei Strings benutzen kann. Gerade auf dem "Kleinen" wie den UNO. Daher habe ich mich selbst dazu genötigt, auf Strings und Fremd-Classes so weit wie es mein Kenntnisstand erlaubt zu verzichten. Nur dadurch bekomme ich meine Progis wirklich in den Griff und stolper nur noch gelegentlich und kurzfristig über das eine oder andere.

Wie gesagt, wenn Leute man lernen würden dass reserve() existiert und was das bedeutet, wäre es nicht so schlimm. Das ist wie in OOP Sprachen wie man eine leere Collection anlegen kann und deren Größe vom Compiler verwalten lässt, oder man fängt mal mit 10 Objekten an weil man weiß dass man diese gleiche braucht (wobei man da sagen muss der der Wachstums-Algorithmus dieser Collections intelligenter ist als das Array jedesmal nur um 1 zu vergrößern).

Eine gute Option ist diese Klasse:
http://arduiniana.org/libraries/pstring/
Damit kann man print()/println() verwenden um in char Arrays zu schreiben. Man hat also nicht diesen Speicher-Irrsinn, aber trotzdem Komfort

Ein interessanter Link,
den werde ich mir kurzfristig näher anschauen!
Besten Dank für die Info.

PS:
Wollte ich anfangs nur ein paar LEDs zum Blinken bringen und ein paar Schalter abfragen...
steckte ich heute kopfüber viel tiefer im µC als ich je zu träumen gewagt hatte.
:wink:

Serenifly:
Eine gute Option ist diese Klasse:
PString | Arduiniana
Damit kann man print()/println() verwenden um in char Arrays zu schreiben. Man hat also nicht diesen Speicher-Irrsinn, aber trotzdem Komfort

Vor allem in Verbindung mit der Streaming.h
Mann sollte nur nicht vergessen, die PString Variable vor dem wiederverwenden zu leeren, weil alles hinten angesetzt wird.

Erstmal danke für das viele hilfreichende Feedback. Ich habe nun mein Problem ausmachen können.
In meiner Webserver Funktionen habe ich einen 13stelligen Wert in ein char[13] Feld geballert (keine Reserve für den "\n") Schäm-Modus :roll_eyes: . Das hat aber bereots seit x Entwicklungsstunden funktioniert und mit der neuen Funktion, die damit 100% nix zu tun hat, sich bemerkbar gemacht.

Ich habe dann das char array auf die richtigen größe gebracht char[14] und alles lief, ohne die merkwürdigen Sonderzeichen.

Was ich nur nicht verstehe ist, dass der Fehler jetzt erst auftaucht...
War schoon immer so und bleibt so, macht mans richtig funktionierts auch :wink:

Die pstring Library werde ich mich auch mal anschauen, klingt interessant.

Danke!
Andy

Du meinst eher den NULL-Terminator. C Strings sind am Ende mit NULL terminiert, damit man das Ende feststellen kann. Das Array muss daher mindestens eins größer als die Anzahl der sichtbaren Zeichen sein

Hmm ...

Das Array muss daher mindestens eins größer als die Anzahl der sichtbaren + unsichtbaren Zeichen sein.
Denn ich zähle \n zu den unsichtbaren. Zu den Steuerzeichen.

Das Array muss daher mindestens eins größer als die max. Anzahl der zu speichernden Zeichen sein. Alles ungleich 0 ist ein Zeichen bzw. Steuercode