Stack-Speicher wieder leer bekommen

Hi zusammen,

sorry, dass ich euch heute so mit Fragen / Posts bombadiere.

Aber ich hab wieder mal ne Grundwissen-Frage ... :grimacing: ... ich weiß...eigentlich ist das hier nicht der richtige Ort für solche Fragen, aber ich trau mich trotzdem wieder mal, euch zu nerven und freue mich, wenn sich jemand erbarmt :innocent:

Wie bekomm ich denn den Stack-Speicher (z.B. des Loop-Tasks) wieder leer, wenn ich den mal zugemüllt habe.

Folgender Beispiel-Code (völlig sinnfrei, nur zur Veranschaulichung):

#include <Preferences.h>
Preferences prefs;

typedef struct {
  double wert_eins;
  double wert_zwei;
} test;

test testarray[400]; // Übertrieben großer Array

double wert_eins=0;
double wert_zwei=0;

void setup() {
  Serial.begin(115200);

  prefs.begin("settings", false);
    prefs.clear();
  prefs.end();

}

void loop() {
  set_values(2021, 2.44, 12.44); // Irgendwas reinfüllen
  get_values(2021); // Und irgendwas abrufen --> Schwups, ist der Speicher voll
  
  Serial.printf("\nFreier Stack-Speicher: %d", uxTaskGetStackHighWaterMark(NULL));
  Serial.println();
  Serial.print("Wert eins:");Serial.println(wert_eins);
  Serial.print("Wert zwei:");Serial.println(wert_zwei);
  
  memset(testarray, 0, sizeof(testarray));// Versuch zwei, den Stack wieder zu leeren
  
  Serial.printf("\nFreier Stack-Speicher: %d", uxTaskGetStackHighWaterMark(NULL));

  delay(5000);
}


void get_values(uint16_t jahr) {
  // Werte ausgeben
  prefs.begin("settings", false);
    size_t schLen = prefs.getBytes("values_set", NULL, 0);
    char buffer[schLen];
    prefs.getBytes("values_set", buffer, schLen);
    memcpy(testarray, buffer, schLen);

    wert_eins=testarray[jahr-2021].wert_eins;
    wert_zwei=testarray[jahr-2021].wert_zwei;

    memset(buffer, 0, sizeof(buffer)); // Versuch eins, den Stack wieder zu leeren
  prefs.end();
}

void set_values(uint16_t jahr, double wert_eins, double wert_zwei) {
  // Werte speichern
  prefs.begin("settings", false);
    testarray[jahr-2021].wert_eins=wert_eins;
    testarray[jahr-2021].wert_zwei=wert_zwei;
    prefs.putBytes("values_set", &testarray, sizeof(testarray));
  prefs.end();
}

mit

memcpy(testarray, buffer, schLen);

pack ich ja quasi den (hier völlig überdimensionierten Array) in einen Char Buffer.

Ab dann ist der Stack quasi voll.

Wie bekommt man den denn dann wieder leer.
Ich dachte mit

memset(buffer, 0, sizeof(buffer));

würde ich den Buffer wieder leer machen und somit Stack-Speicher zurückgewinnen - hat aber natürlich nicht funktioniert ;-(

Daher die Frage:
Wie bekomme ich den Array wieder aus dem Stack "raus"?
Könnte ja sein, ich will nur ein paar Werte aus dem Array in lokale Variablen laden (wie ich es hier in dem Beispiel mache) und dann den Array-Inhalt wieder raus haben wollen (denn der ist ja in den Prefs gespeichert und liegt da griffbereit)

Danke für eure Hilfe :innocent:

Vermutlich meinst Du den Heap Speicher, nicht den Stack? Der Stack wird beim Verlassen einer Funktion automatisch komplett aufgeräumt.

Den vom Heap besorgten Speicher kann man ebenso automatisch freigeben lassen, wenn man den Pointer in eine Klasse packt, bei Bedarf ein Objekt dieser Klasse erzeugt, das dann beim Verlassen seines Lebensbereichs (Funktionsende) auch automatisch gelöscht wird, und sein Destruktor gibt dann auch den Speicher im Heap frei.

Auf den kleineren Arduinos mit wenig RAM funktioniert die dynamische Speicherverwaltung nicht so richtig. Man darf sich dort nicht darauf verlassen, daß der Speicher tatsächlich freigegeben und zur Wiederverwendung verfügbar wird.

Darf ich dich fragen, warum du hier memcopy verwendest, und nicht eine Zuweisung?
OK, ich ahne die Antwort schon...
(sach nix)

Aus Erfahrung möchte ich dir sagen:
Mit stochern im Nebel wirst du bestenfalls mal ein zufällig positives Ergebnis bekommen.
Da kannst du Monate lang buddeln und stochern.
Das ist für dich Frustrierend, und je mehr Threads du aufmachst, auch für uns.

Hi,

Aber warum gibt mir dann das hier

nach Ausführung der Funktion immer noch 116 als freien Speicher zurück?

Serial.printf("\nFreier Stack-Speicher: %d", uxTaskGetStackHighWaterMark(NULL));

Die Funktion gibt doch den Freien Stack-Speicher zurück, zumindest lässt der Funktionsname das vermuten.

Ok....:grimacing: hast du da ein Beispiel?

Nein!
Lässt es nicht.

Das Beispiel mit memcpy hatte ich genau so mal hier (oder wahrscheinlich eher in einem anderen Forum) gefunden. Da gings drum, wie man Werte in einem Array in den Preferences ablegen und später wieder abrufen kann. Ich wollte das zum Ablegen diverser Einstellwerte nutzen und es erschien mir als gute Lösung. Ich such grad schon nach dem Post. Aber dann war der Ersteller des Beispiels wohl der gleiche Narr wie ich :wink:

Ich will halt sowas hier dauerhaft speichern (also auch wenn mal der Strom vom ESP weg ist).
Dafür kamen mir die Preferences als Praktisch vor:


typedef struct {
  uint16_t wert_eins;
  uint16_t wert_zwei;
  ... usw.... insgesamt ca. 10 - 15 Werte
} testarray;

testarray wertespeicher[20];

D.h. ich kann deinen einen 2-dimensionalen Array mit 20 Elementen à 10-15 Werten ablegen.

Und das hat mit dem Beispiel aus dem Forum sehr gut funktioniert.
Nur eben die Sache mit dem vollgelaufenen Speicher stört mich.

OK, dann habe ich diesen Beispiel-Sketch falsch verstanden:

Sorry, aber deine Antwort hat keinen Bezug zu meiner Frage!

Sieht so aus!

Wenn du wissen wollen würdest, wie solche Stack Wassermarken gebaut werden können, dann würdest du gleichzeitig den(einen) Fehler in deinen Annahmen finden.

Nachtrag:
Das Beispiel ist ok, deine Annahmen nicht.

Dann ist aber die Kommentierung in dem Beispiel-Sketch schon echt irreführend:

Mein Englisch ist nicht das Beste aber "print unused stack" hatte ich mir "Gib den freien Stack-Speicher aus" übersetzt. Fiese Sache, wenn das dann nicht stimmt.

Will ich doch!

Nein, es ist deine irrige Annahme, welche dich in die irre führt!

Es ist deine Annahme, welche nicht stimmt!

Lass dir den Satz von Google oder wem auch immer übersetzen,

Schon, aber Du hast ja auch nur Heap-Speicher belegt. Versuchs mal mit der Abfrage des freien Heap Speichers (memavail?).

OK, heap oder stack sei mal dahin gestellt.

Jedenfalls gibt die oben erwähnte Funktion

Serial.printf("\nSetup() - Free Stack Space: %d", uxTaskGetStackHighWaterMark(NULL));

(ich werde eine Umbenennung in "uxTaskGetHeapHighWaterMark" beantragen :slight_smile: )

mir nach dem memcpy-Befehl (der anscheinend auch nicht wirklich passend ist) zurück, dass von meinen ursprünglich 68xx Bytes nur noch 116 übrig sind.

D.h. hier ist ein Speicher - nennen wir ihn Heap - vollgelaufen.
Den muss man doch nun auch wieder leer bekommen.
Und darauf zielt meine Frage ab.

@combie Ich weiß, dass wir die Diskussion über mein fehlendes Wissen immer wieder führen. Es tut mir auch echt leid. Aber ich bin halt einer vom Typ "Ins kalte Wasser springen und losschwimmen":

Klar wäre es vielleicht besser, erstmal einen C++ Grundkurs zu besuchen oder in irgendwelchen Büchern zu wälzen. Aber manchmal ist learning by doing auch ein Weg. Und ob du es glaubst oder nicht: Ich persönlich lerne so am meisten. Und ich hab auch schon jede Menge gelernt - vor allem auch durch eure Hilfe. Aber ich verstehe auch dass das nicht bei jedem auf Verständnis stößt.

Ich bring einfach nochmal das Beispiel von dem Tag an dem ich meinen Vater gefragt habe, wie man Ski fährt und er dann gesagt hat "Probiers einfach" und mir dann einen Schupser in Richtung Piste gegeben hat...". Ich hab da vorher keine Bücher gelesen und auch keine YouTube-Video geschaut ... vor allem weil es die noch gar nicht gegeben hat :slight_smile:

Aber ich will das ja jetzt alles auch gar nicht zum Thema machen.
Ich googel mal und kuck, ob ich in irgendeinem Buch die Antwort finde.

Danke euch trotzdem :smiling_face_with_three_hearts:

Tipp:
Nicht alles was hinkt, ist ein Vergleich!

Was denn jetzt?
Heap oder Stack?

Wir können Ihn auch Dieter nennen.
Hauptsache wir bekommen ihn wieder leer @combie :sweat_smile:

Wenn du die beiden durcheinander wirfst, ist unsere Kommunikation zum scheitern verurteilt.

@combie du bist echt ein verrücktes Huhn!

Aber ok, ich nehms mit Humor und sag Gute Nacht allerseits!

Bahnhof!

Und, ausgeschlafen?

Den Satz von gestern mal durch Google gejagt und bemerkt was an deiner Übersetzung falsch ist?


Einspruch: Nein, das stimmt nicht!
Das steht so nicht in der Doku.
Das steht so nicht im Beispiel.
Das ist reines Wunschdenken(eine Illusion) des @basementmedia

Die Funktion weiß nichts darüber, wieviel Stack Speicher frei ist.

Das mag ein pingeliges Detail in der Betrachtungsweise sein, ist aber hier maßgeblich für den Irrtum verantwortlich.

Dir ist schon bewusst, dass 'heap' und 'stack' 2 vollkommen unterschiedliche Bereiche im Speicher sind ? Wenn Du den einen verbrauchst, kannst Du nicht erwarten, dass dir das beim anderen angezeigt wird.