Hi, bin nun schon seit einigen auf der Suche nach einem blöden Fehler. Nach Stunden fehlerfreier Funktion kommt plötzlich ein ovf und er hängt.
Ist ein sehr umfangreicher Sketch, der seit nun schon Jahren im Dauer provisorisch Betrieb läuft.
Das Problem begann, als ich von dht22 auf bme280 mit adafruit lib umgestiegen bin. Die bme280 Routine läuft standalone tagelang ohne Probleme.
Ich habe viele debug Ausgaben drin, auch die Ausgabe von free Ram. Normalerweise so 3300 bytes free. Teilweise kam dann 22 bytes free und das wars, aufgehängt, manchmal noch eine ovf in der debug ausgabe von einer Variablen.
Er hängt sich auch immer an verschiedenen Stellen auf, zumindest lassen die debug Ausgaben darauf schließen. Aufgrund exzessivem Gebrauch von INTERVAL konnte ich jedoch bisher nicht sicher herausfinden, ob es vielleicht doch eine bestimmte Stelle im Sketch ist.
Kommentiere ich nun im loop genügend Programmteile aus, läuft alles. Unabhängig was ich deaktiviere, Hauptsache der Programmteil ist gross genug.
Der Umstieg auf bme280 fiel auch mit einem Tausch des Mega2560 zusammen. Daher kommt mir der Verdacht, ob evtl. die Hardware was hat.
Irgend eine Idee, was ich noch probieren kann?
Momentan hab ich leider keinen 2. Mega zum tauschen verfügbar.
Gibt es einen Testsketch, der das RAM prüft?
P.s.: Der Sketch ist dermaßen umfangreich, macht zunächst noch keinen Sinn, den zu posten. String Objekte werden nicht benutzt.
Ich kann den Code schon posten, aber ich mach jede Wette, dass du ihn nicht komplett durchsiehst. Ich nehm später die persönlichen Daten raus und packe es in ein zip.
Rekursion benutze ich hier nicht.
Wie gesagt, es kam ja schon ovf, stack overflow anstatt des Variablenwertes bei der debug Ausgabe.
Richtig hingeschaut hab ich auf die Änderung beim einpflegen des bme280 codes. Der Rest blieb ja unberührt.
ElEspanol:
Irgend eine Idee, was ich noch probieren kann?
nur was mir so auffällt, was zwar nicht die Ursache sein muss - aber sicher nicht förderlich ist:
Das F-Makro wendest du nicht konsequent an, und geschätzte 10% deiner Fixtexte stehen noch im RAM
Im Webclient machst du mir zu viele Ausgaben
Die Routinen, in denen noch String Objekte sind, werden momentan nicht genutzt, werde es aber mit der Zeit noch umbauen.
Die paar Bytes wegen dem F Macro reissen es nicht raus, muss ich aber auch mal noch ändern. Sind aber noch über 3000 bytes frei.
Ich habe jetzt an vielen Stellen noch eine Routine angesprungen, die verschiedene Statusmeldungen ausgibt, wenn freememory<100. und noch mehr debug Ausgaben.
Nun läuft das Ding schon fast 24 Stunden ohne Fehler.
Referenzen solltest du inzwischen eigentlich kennen und wissen dass man Objekte i.d.R. nicht als Kopie übergibt
Der Compiler ist normal in der Lage die Kopie beim Rückgabewert wegzuoptimieren (Stichworte "copy elision" und "return value optimization"), aber das ist dann auch unnötig, da man den übergebenen String in der Funktion ändern kann
Evtl. muss man dann aber Teil-Strings zwischenspeichern. Ist also vielleicht nicht unbedingt so viel besser
Diese Altlasten in dem Sketch muss ich noch beseitigen, da sind teilweise noch Programmteile aus meinen Anfangszeiten drin. Ich finde es klasse, dass sich doch jemand diesen umfangreichen verschachtelten Code ansieht. Aber ich bin mir ziemlich sicher, dass das alles nicht die Ursache des Problems ist. Der Sketch lief jetzt das letzte Mal über 90.000 Sekunden, bis er sich verabschiedet hat. Vor dem Einbau der weiteren debug Massnahmen lief er wesentlich kürzer.
Und das freememory war IMMER gleich mit 3.306 oder so, deswegen glaube ich nicht an die String Theorie. Das Logfile hat fast 16 Megabyte. Werde das letzte Mb nachher mal hochladen. Die Meldung mit freememory = 22 bekomme ich nicht mehr. Vermutlich kackt er vorher ab.
Bevor ich nun weitere Änderungen mache, will ich den nächsten Absturz abwarten, was das Log sagt.
Und wenn alles nix hilft, aus einer anderen Installation testweise einen Mega entführen.
Ich muss gestehen, dass ich mir das auch angesehen habe, aber nicht durchblicke.
Offensichtliche Fehler kann ich so nicht entdecken.
Also habe ich nur ein paar allgemeine Aussagen für dich.
Du arbeitest viel mit Buffern, und füllen der Buffer.
Dort eine Bereichsüberschreitung, und es knallt.
Aus eigener leidlicher Erfahrung weiß ich, wie gut sich solche Fehler verstecken können.
availableMemory() sagt zwar wie groß der größte zu reservierende Block ist, sagt aber nichts über den Stackbedarf. Auch wenn ich/du keine offensichtliche Rekursion sehen, heißt es nicht, dass keine da wäre.
Tipp zu Verwendung der String Klasse:
Man kann in setup() dafür Platz reservieren, so dass die automatische Reservierung vermeidbar ist.
Log von heute (putty-verkurzt.log, ca. 8,5 Mbyte gross, keine Auffälligkeiten, bis dann am Schluss die Sache komisch wird.
Die "St=0^^^^^^^^^ ..... ^㠠 Free RAM: 3309" ist eine Zeile mit fast 200.000 Zeichen Länge
Die Meldung "Free RAM: 3309" ist eine andere serielle Ausgabe, wurde nicht zusammen mit der St= geschickt.
Nach millis=45.406.532, das sind ca. 15 Stunden
Log von gestern, putty1-verkurzt:
Auch hier die letzten Zeilen ewig lang. Absturz nach über millis=90.104.677, das sind ca. 30 Stunden
Die Hardware wurde nicht angefasst, sie steht remote in einem Technikraum.
Ich hab jetzt mal ein char array mit 2000 Zeichen angelegt, so dass nur noch 1265 freememory da sind. Mal sehen, was passiert.
"Der Sketch verwendet 82170 Bytes (32%) des Programmspeicherplatzes. Das Maximum sind 253952 Bytes.
Globale Variablen verwenden 6755 Bytes (82%) des dynamischen Speichers, 1437 Bytes für lokale Variablen verbleiben. Das Maximum sind 8192 Bytes.
Wenig Arbeitsspeicher verfügbar, es können Stabilitätsprobleme auftreten."
Hier mal ein Beispiel, für einen potentiellen Bufferüberlauf.
Zumindest lässt du keinen Platz für das Null Byte, welches als Stringende unabdingbar ist.
Udp.read(incomingbuffer, sizeof(incomingbuffer));
Und der darauffolgende
pos = strstr(incomingbuffer, "#200M");
Kann Vollgas vor die Wand fahren.
Bzw., bis ins endlose, bis er ein zufälliges Nullbyte findet.
Tipp 1:
Udp.read() hat einen Rückgabewert, nutze diesen als Richtwert für das zu setzende Nullbyte. Dann sparst du dir auch das ewige löschen des Buffers.
Tipp 2:
Um Platz zu schaffen, für das Nullbyte, welches du beständig ausblendest:
-> Udp.read(incomingbuffer, sizeof(incomingbuffer)-1);
Zum Testen: Setze später mal das 2000-Byte-Array ganz an den Anfang als erste Deklaration, so dass es zwar den Speicher verknappt, aber keinen Raum für Überlaufe schafft.