Memory Leak When Ending/Resetting
Versions
Board: ESP32
Arduino IDE: 1.8.19
Arduino ESP32 core version: 2.0.4
ESPAsyncWebServer: 1.2.3
Issue
When I start the server for the first time it takes a good size chunk of RAM. This is fine and expected. When I end the server it doesn't give back all the memory that it used. Every start and end after this takes roughly the same amount of memory and also gives it back. So it seems that the first start takes memory and holds it and it doesn't get freed.
Code Showing Issue
#include <cstdint>
#include <ESPAsyncWebServer.h>
#include <ESPmDNS.h>
#include <ezButton.h>
#include <WiFi.h>
const uint8_t page_length{70};
const uint8_t page[] PROGMEM = {
31, 139, 8, 8, 22, 115, 43, 99, 0, 3, 105, 110, 100, 101, 120,
95, 109, 105, 110, 46, 104, 116, 109, 108, 0, 179, 81, 76, 201, 79,
46, 169, 44, 72, 205, 40, 201, 205, 177, 179, 41, 176, 243, 72, 205,
201, 201, 215, 81, 8, 207, 47, 202, 73, 81, 180, 209, 47, 176, 227,
2, 0, 8, 9, 148, 205, 35, 0, 0, 0
};
AsyncWebServer server{80};
ezButton button{25};
void setup()
{
Serial.begin(115200);
button.setDebounceTime(50);
Serial.print("Initial: ");
Serial.println(ESP.getFreeHeap());
// Pinning to core 0, as I have issues when starting WiFi on core 1
xTaskCreatePinnedToCore(
task,
"Main Controller",
10000,
NULL,
5,
NULL,
0);
}
void loop()
{
vTaskDelete(NULL);
}
void task(void*)
{
while (true)
{
button.loop();
if (button.isPressed())
{
start_server();
Serial.print("Server started: ");
Serial.println(ESP.getFreeHeap());
}
else if (button.isReleased())
{
end_server();
Serial.print("Server ended: ");
Serial.println(ESP.getFreeHeap());
}
// Don't block the idle task
delay(1);
}
}
void start_server()
{
static const char* ssid{"fancy_name"};
static const char* password{"secretpass"};
// Access point
WiFi.mode(WIFI_AP);
// Max 1 connection
WiFi.softAP(ssid, password, 1, 0, 1);
MDNS.begin(ssid);
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/a", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/b", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/c", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/d", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/e", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/f", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/g", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/h", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/i", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.on("/j", HTTP_GET, [](AsyncWebServerRequest *request)
{
AsyncWebServerResponse *response = request->beginResponse_P(
200, "text/html", page, page_length);
response->addHeader("Content-Encoding", "gzip");
request->send(response);
});
server.onNotFound([](AsyncWebServerRequest *request) {request->send(404);});
server.begin();
}
void end_server()
{
server.end();
server.reset();
MDNS.end();
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_OFF);
}
I use a button to start and stop the server and use ezButton just to make it easier. The button can be removed and it can be started and stopped every 1-2 seconds for example.
Output
You can see after the server ends, it never gets above 265100.
Initial: 297260
Server started: 231960
Server ended: 265100
fancy_name
Server started: 231784
Server ended: 265100
Code "Without" Issue
#include <cstdint>
#include <ESPAsyncWebServer.h>
#include <ESPmDNS.h>
#include <ezButton.h>
#include <WiFi.h>
const uint8_t page_length{70};
const uint8_t page[] PROGMEM = {
31, 139, 8, 8, 22, 115, 43, 99, 0, 3, 105, 110, 100, 101, 120,
95, 109, 105, 110, 46, 104, 116, 109, 108, 0, 179, 81, 76, 201, 79,
46, 169, 44, 72, 205, 40, 201, 205, 177, 179, 41, 176, 243, 72, 205,
201, 201, 215, 81, 8, 207, 47, 202, 73, 81, 180, 209, 47, 176, 227,
2, 0, 8, 9, 148, 205, 35, 0, 0, 0
};
AsyncWebServer server{80};
ezButton button{25};
void setup()
{
Serial.begin(115200);
button.setDebounceTime(50);
Serial.print("Initial: ");
Serial.println(ESP.getFreeHeap());
// Pinning to core 0, as I have issues when starting WiFi on core 1
xTaskCreatePinnedToCore(
task,
"Main Controller",
10000,
NULL,
5,
NULL,
0);
}
void loop()
{
vTaskDelete(NULL);
}
void task(void*)
{
while (true)
{
button.loop();
if (button.isPressed())
{
start_server();
Serial.print("Server started: ");
Serial.println(ESP.getFreeHeap());
}
else if (button.isReleased())
{
end_server();
Serial.print("Server ended: ");
Serial.println(ESP.getFreeHeap());
}
// Don't block the idle task
delay(1);
}
}
void start_server()
{
static const char* ssid{"fancy_name"};
static const char* password{"secretpass"};
// Access point
WiFi.mode(WIFI_AP);
// Max 1 connection
WiFi.softAP(ssid, password, 1, 0, 1);
MDNS.begin(ssid);
}
void end_server()
{
MDNS.end();
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_OFF);
}
Output
You can see that the initial is the same, and when the end_server function is called the free RAM goes back up much closer than it did when using ESPAsyncWebServer. Although it does show that there is possibly a similar but smaller issue with WiFi or MDNS.
Initial: 297620
Server started: 250872
Server ended: 282456
fancy_name
Server started: 250704
Server ended: 282448
It is very possible that I am not ending the server properly, but I can't find anything in the documentation about it.
[STALE_SET] This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.
I saw something similar. Every time I create/delete a new server instance, some memory is leaked. I suspect on the handlers not being always properly freed. This is what I tried:
- create:
new server - set handlers:
server.on(...) - start the server:
server.begin() - after 2 or 3 minutes, and without doing any request to the server:
delete server - after 1 minute, get back to step 1
On each cycle you lose some memory... unless you omit step 2
[STALE_CLR] This issue has been removed from the stale queue. Please ensure activity to keep it openin the future.