[Résolu] Esp32 RtOs et JsonSerialize, fuite mémoire?

Bonjour a tous,

Je rencontre un problème de fuite mémoire quand je fais un serializeJson dans la callback d'une xTaskCreate. Alors la mémoire ne tombe pas à 0 mais sur les 170K de ram dispo au début de l'execution, on se retrouve avec 30K apres quelques milliers d'itérations.

Voici le code minimaliste pour reproduire la bug

#include <Arduino.h>
#include <WiFi.h>
#include <LittleFS.h>
#include <ArduinoJson.h>

void showMemoryUsage(int iteration);

DynamicJsonDocument * list_json_doc;

int loops = 0;

void setup() {
    Serial.begin(115200);
    String json_string = "[{\"name\":\"Network 1\",\"password\": \"password1\"},{\"name\": \"Network 2\",\"password\": \"password2\"},{\"name\": \"Network 3\",\"password\": \"password3\"}]";
    list_json_doc = new DynamicJsonDocument(1024);
    deserializeJson(*list_json_doc, json_string);
}


void loop() {

    if (loops % 100 == 0) {
        showMemoryUsage(loops);
    }

    // TEST Without Task
    // String response;
    // serializeJson(*list_json_doc, response);


    // TEST With Task
    if (loops < 2000) {
        xTaskCreate(
            [](void *arg){
                String _response;
                DynamicJsonDocument * _list = (DynamicJsonDocument*)arg;
                serializeJson(*_list, _response);
                vTaskDelete(NULL);
            },
            "handler",
            5000,
            (void*)list_json_doc,
            1,
            NULL
        );
    }

    delay(10);
    loops++;
}


void showMemoryUsage(int iteration) {
    multi_heap_info_t info;
    heap_caps_get_info(&info, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
    Serial.print("iteration: ");
    Serial.print(iteration);
    Serial.print("\tTotal Free: ");
    Serial.print(info.total_free_bytes);
    Serial.print("\tMinimum free: ");
    Serial.print(info.minimum_free_bytes);
    Serial.print("\tLargest free block: ");
    Serial.println(info.largest_free_block);
}

Voici ce que ca me sort comme log

iteration: 0    Total Free: 270224      Minimum free: 264688    Largest free block: 118772
iteration: 100  Total Free: 254224      Minimum free: 243860    Largest free block: 118772
iteration: 200  Total Free: 238224      Minimum free: 232340    Largest free block: 110580
iteration: 300  Total Free: 222224      Minimum free: 216340    Largest free block: 110580
iteration: 400  Total Free: 206224      Minimum free: 200340    Largest free block: 110580
iteration: 500  Total Free: 190224      Minimum free: 184340    Largest free block: 110580
iteration: 600  Total Free: 174224      Minimum free: 168340    Largest free block: 110580
iteration: 700  Total Free: 158224      Minimum free: 152340    Largest free block: 110580
iteration: 800  Total Free: 142224      Minimum free: 136340    Largest free block: 110580
iteration: 900  Total Free: 126224      Minimum free: 120340    Largest free block: 110580
iteration: 1000 Total Free: 110224      Minimum free: 104340    Largest free block: 94196
iteration: 1100 Total Free: 94224       Minimum free: 88340     Largest free block: 77812
iteration: 1200 Total Free: 78224       Minimum free: 72340     Largest free block: 61428
iteration: 1300 Total Free: 62224       Minimum free: 56340     Largest free block: 38900
iteration: 1400 Total Free: 46224       Minimum free: 40340     Largest free block: 23028
iteration: 1500 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 1600 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 1700 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 1800 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 1900 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2000 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2100 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2200 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2300 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2400 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2500 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2600 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2700 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2800 Total Free: 30864       Minimum free: 24980     Largest free block: 4980
iteration: 2900 Total Free: 30864       Minimum free: 24980     Largest free block: 4980

J'arrete de créer de nouvelles tâckes à la 2000 itération pour vérifier si la mémoire remonte toute seule si j'arrete de créer de nouvelles tâches, mais comme on voit sur le log ca reste pareil.

A noter que quand je n'utilise pas la tache mais que je serializeJson directement dans ma loop, aucune fuite mémoire.

Pour info j'utilise ArduinoJson6.

Auriez vous des idées?

Merci par avance

A quoi sert de créer ces tasks ? Si ça fonctionne dans la loop, pas besoin d'en faire plus.
Sinon, la fuite mémoire est probablement dûe à la mémoire réservée pour la task, l'argument 5000 de la création de la task.
Il faudrait libérer cette mémoire après la fin de la task et la tuer avec

vTaskDelete(NULL);

à la fin.

@lesept Merci pour ta réponse, alors en fait c'est un extrait minimisé et opérationnel pour mettre en avant l'anomalie que j'observe. Bien évidemment le code tel quel n'a pas d'utilité. Dans la réalité j'ai besoin de créer une tache pour faire une opération lente en réponse a une route serveur.

Pour info le

vTaskDelete(NULL);

est bien appelé a la fin de ma callback

Aussi autre indice: Si je fais pas de serilizeJson j'ai pas de problème avec les tâches. J'veux dire par là que tout autre opération dans le callback de tache ne crée pas de "fuite" mémoire

Peut-être faut il faire un clear ?

Est-ce que tu obtiens les mêmes chiffres si tu changes la valeur 1024 ?

Je pense que ton problème est similaire a ce qui est présenté ici

Avec trois possibilités de correction.

Haha Merci!!! @lesept Alors j'ai déjà vu tout ca et joué avec.

Mon document ne grossit pas. j'avais checké la mémoire occupée par le document dans chaque tâche et elle reste stable. J'avais essayé aussi les garbage collect et autres ca n'a pas d'effet en effet. Le clear par contre va me reinitialiser le doc pointé. Donc a la prochaine itération je ne l'aurais plus.

Sinon l'histoire connue du l'histoire de la lib json si j'ai bien compris, c'est surtout quand tu le modifie. Si tu le modifie pas ou que tu le crée a chaque fois, pas de probs normalement....

Sinon a titre de test j'ai changé

    list_json_doc = new DynamicJsonDocument(512);

Les résutats sont sensiblement les mêmes

iteration: 200  Total Free: 238724      Minimum free: 232840    Largest free block: 110580
iteration: 300  Total Free: 222724      Minimum free: 216840    Largest free block: 110580
iteration: 400  Total Free: 206724      Minimum free: 200840    Largest free block: 110580
iteration: 500  Total Free: 190724      Minimum free: 184840    Largest free block: 110580
iteration: 600  Total Free: 174724      Minimum free: 168840    Largest free block: 110580
iteration: 700  Total Free: 158724      Minimum free: 152840    Largest free block: 110580
iteration: 800  Total Free: 142724      Minimum free: 136840    Largest free block: 110580
iteration: 900  Total Free: 126724      Minimum free: 120840    Largest free block: 110580
iteration: 1000 Total Free: 110724      Minimum free: 104840    Largest free block: 94196
iteration: 1100 Total Free: 94724       Minimum free: 88840     Largest free block: 77812
iteration: 1200 Total Free: 78724       Minimum free: 72840     Largest free block: 61428
iteration: 1300 Total Free: 62724       Minimum free: 56840     Largest free block: 45044
iteration: 1400 Total Free: 46724       Minimum free: 40840     Largest free block: 23028
iteration: 1500 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 1600 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 1700 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 1800 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 1900 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 2000 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 2100 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 2200 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 2300 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 2400 Total Free: 30884       Minimum free: 25000     Largest free block: 4980
iteration: 2500 Total Free: 30884       Minimum free: 25000     Largest free block: 4980

Ok je crois que j'ai résolu mon problème

Le soucis ici c'est que le vTaskDelete a du mal à cleaner son propre contexte. En gros la mémoire de la tâche n'est pas correctement désalouée surtout quand on utilise des String et autres trucs dans le genre

Ca se corige en créeant un contexte local dans la callback

    // TEST With Task
    if (loops < 2000) {
        xTaskCreate(
            [](void *arg){
                {
                    String _response;
                    DynamicJsonDocument * _list = (DynamicJsonDocument*)arg;
                    serializeJson(*_list, _response);
                }
                vTaskDelete(NULL);
            },
            "handler",
            5000,
            (void*)list_json_doc,
            1,
            NULL
        );
    }

Le contexte parent reste accessible, et dans le contexte de la call back a part le sous contexte on ne laisse que le vTaskDelete(NULL). Si je comprends bien ca permet de forcer la desalocation propre de la mémoire occupée par la tâche.

Donc le problème est réglé ? Qu'est-ce que ça donne dans la console ?

Alors dans mon cas minimaliste oui le problème est réglé. Si j'ai bien identifié et circoncis l'anomalie, ca veut dire que c'est bien réglé dans mon serveur aussi, je testerais ce soir

Et la console ca donne ca maintenant:

iteration: 0    Total Free: 270224      Minimum free: 264688    Largest free block: 118772
iteration: 100  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 200  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 300  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 400  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 500  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 600  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 700  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 800  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 900  Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1000 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1100 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1200 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1300 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1400 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1500 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1600 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1700 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1800 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 1900 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2000 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2100 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2200 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2300 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2400 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2500 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2600 Total Free: 270224      Minimum free: 259312    Largest free block: 118772
iteration: 2700 Total Free: 270224      Minimum free: 259312    Largest free block: 118772

Merci pour ton aide, reformuler le problème et interagir autour avec d'autres est toujours tres prolifique =)

Super ! Bonne continuation !

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.