michalmonday / CSV-Parser-for-Arduino

It turns CSV string into an associative array (like dict in python)
MIT License
58 stars 12 forks source link

Memory leak when using readSDfile function #12

Closed foster066 closed 2 years ago

foster066 commented 2 years ago

Thank you for your awesome library. I'm using ESP32 Dev Kit v1 with SD Card connected to HSPI (this is reflected in test project). Also I use readSDfile which covers all the basis. I haven't use other ways of parsing. The issue happens with other files as well. The test is very simple - just open and close the file and observe memory leak around ~50-60 bytes each heap printout. My main scenario that some csv files are parsed periodically and each time I observe this memory leak. Sample project:

void loop() {
  // put your main code here, to run repeatedly:
  CSV_Parser parser("sssss", true, ';');
  if (parser.readSDfile(SUN_DATA_FILE))
  {
    Serial.println("File is parsed");
  }
  else
  {
    Serial.printf("File %s is not found\n", SUN_DATA_FILE);
  }
  delay(2000);
  if (timer.tick())
  {
    Serial.printf("Free heap size: %d\n", xPortGetFreeHeapSize());
  }
}
Print out from the sample project:
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 255168
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 254864
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 254620
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 254408
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 254152
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 253908
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 253644
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 253368
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 253180
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 252940
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 252704
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 252464
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 252208
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 251932
File is parsed
File is parsed
File is parsed
File is parsed
File is parsed
Free heap size: 251692
foster066 commented 2 years ago

Sample project attached CsvMemoryLeak.zip data.zip

foster066 commented 2 years ago

Hi @michalmonday, Any updates on this issue?

michalmonday commented 2 years ago

Hello, thanks a lot for reporting this, adding free(is_fmt_unsigned); in destructor seems to fix it. The 0.2.2 version I just created have it patched (probably it will take few hours or a day until it's available through Arduino library manager).

I didn't have Esp with sd card connected but I tested it with the following code on Arduino Pro Mini 5V 328p:

#include <CSV_Parser.h>

#include <SPI.h>
#include <SD.h>

#define SUN_DATA_FILE "sun-gorodez.csv"

const int chipSelect = 10;

void setup() {
  Serial.begin(9600);
  delay(5000);

  Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");

    // don't do anything more:
    while (1);
  }
  Serial.println("card initialized.");

}

// copied from: https://stackoverflow.com/a/8704938/4620679
int availableMemory() {
    int size = 2048;
    byte *buf;
    while ((buf = (byte *) malloc(--size)) == NULL);
        free(buf);
    return size;
}

void loop() {
  // put your main code here, to run repeatedly:
  CSV_Parser parser("sssss", true, ';');
  if (parser.readSDfile(SUN_DATA_FILE))
  {
    Serial.println("File is parsed");
  }
  else
  {
    Serial.println("File parsed");
  }
  delay(2000);
  Serial.println("Free heap size:" + String(availableMemory()));
}

And the output was:

Free heap size:759
File parsed
Free heap size:759
File parsed
Free heap size:759

I'm posting my testing setup because before I fixed the issue, with my setup, each creation of CSV_Parser (each execution of the loop()) decreased the "Free heap size" by exactly 7. In your output it seems that each loop execution decreases the "Free heap size" by much more. I hope this fix solves the problem but please let me know if not.

foster066 commented 2 years ago

I've verified version 0.2.2 and confirm that the issue is fixed. Thank you for your amazing work and the best CSV library for Arduino! Output with version 0.2.2. Zero bytes leak: Free heap size: 211316 File is parsed Free heap size: 211316 File is parsed Free heap size: 211316 File is parsed Free heap size: 211316 File is parsed Free heap size: 211316