Heap Fragmentation Issue on ESP32
Board: Espressif ESP32 Dev Module
Context:
I'm developing a stock control management system using both an offline SQLite3 database (for when there's no connection) and Google Sheets as an online database. The processing is split into two parts:
- The ESP32 reads an NFC tag and constructs a GET request to alter or read data from the online database.
- Google AppScript modifies the database and returns the results as JSON.
Since I'm aiming to make this device as reliable as possible (with no further modifications after deployment), my main concern is heap fragmentation. I've read several articles about this issue, and I want to minimize it as much as possible. I initially tried using arrays of char, but manipulating them became complex, so I plan to explore other methods first.
Questions:
- When I declare a variable globally in Arduino, it is stored in the
.datasegment of RAM, correct? If I then usereserveto allocate memory (e.g., usevarName.reserve(size)insetup()), will it allocate memory from the heap or the data section? I ask this because the answers I found online (including some from ChatGPT) are inconsistent, and I couldn't find many questions directly related to this.
// Global
String payload; // Stored on .bss
String payload2 = "data"; // Stored on .data
// setup
void setup(){
payload.reserve(128); // Is it stored on heap or .bss/.data?
payload2.reserve(128); // Would the old data be deleted?
}
- I'm currently using the following approach to reduce heap fragmentation (though I suspect there may be mistakes). Please review and let me know if you see any issues, and suggest improvements if possible!
- declare null global pointer (to only store the adress of the var in the .data segment);
reservespace in setup function (to have static size, i suppose this will alocate space in theheapsegment);- dereference when needed;
- never
deleteit ("static dynamic allocation?").
Now a bit of the code i'm using, i've removed some parts to make it more concise.
Code:
// Global Variables
String *jsonPayload = nullptr;
String *randomStringArray = nullptr;
String *url = nullptr;
String *accessToken = nullptr;
JsonDocument *doc = nullptr;
// Inside setup()
void setup() {
// Memory allocation
jsonPayload = new String();
jsonPayload->reserve(4096);
accessToken = new String();
accessToken->reserve(1280);
url = new String();
url->reserve(384);
// Random String Array
randomStringArray = new String[2];
randomStringArray[0].reserve(256);
randomStringArray[1].reserve(256);
randomStringArray[0] = "1,stock,4984,Video,Camera,Sony,360pMonster,";
randomStringArray[1] = "1,loan,22,Video,Camera,Sony,360pMonster,22-10-2025 23:59:59";
// JSON Document
doc = new DynamicJsonDocument(4096);
}
// Inside HTTP GET function
String httpGET(const String &decodedData) {
Serial.println("\n\nHTTP Request...\n");
*url = "";
*jsonPayload = "";
*url += BASEURL;
*url += "?values=";
*url += urlencode(decodedData);
Serial.print("\n\nURL ↓\n");
Serial.println(*url);
*accessToken = "Bearer ";
*accessToken += Signer.accessToken();
http.begin(*url);
http.setTimeout(50000);
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
http.addHeader("Authorization", *accessToken);
Serial.print("\n\nAuthorization: Bearer ");
Serial.println(*accessToken);
int httpResponseCode = http.GET();
Serial.println("\n\nResponse Code: " + String(httpResponseCode));
if (httpResponseCode > 0) {
*jsonPayload = http.getString();
Serial.println("\n\nResponse ↓\n" + *jsonPayload);
} else {
Serial.print("↓ Error: ");
Serial.print(httpResponseCode);
}
http.end();
return *jsonPayload;
}
This is my first topic here so excuse me for not providing necessary information, any sugestions are welcome! Also, sorry for bad english!