esp8266 / Arduino

ESP8266 core for Arduino
GNU Lesser General Public License v2.1
16.07k stars 13.33k forks source link

memory leak 184 bytes at a time #1923

Closed yomasa closed 8 years ago

yomasa commented 8 years ago

Basic Infos

looks like 184 bytes get lost every time you post to the page ie :'http://192.168.0.6/gpio/1'

Hardware

Hardware: ESP-12, wemos mini, esp-7 Core Version: 2.2.0-rc1

memory leak?

using the example sketch WifiWebServer added one line of code at the end of sketch

Serial.println( ESP.getFreeHeap(),DEC);

Settings in IDE

Module: wemos mini Flash Size: ?4MB/1MB? CPU Frequency: ?80Mhz? Flash Mode: ?qio? Flash Frequency: ?40Mhz? Upload Using: ?OTA / SERIAL? Reset Method: ?ck / nodemcu?

Sketch

/*

const char* ssid = "your-ssid"; const char* password = "your-password";

// Create an instance of the server // specify the port to listen on as an argument WiFiServer server(80);

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

// prepare GPIO2 pinMode(2, OUTPUT); digitalWrite(2, 0);

// Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected");

// Start the server server.begin(); Serial.println("Server started");

// Print the IP address Serial.println(WiFi.localIP()); }

void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; }

// Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); }

// Read the first line of the request String req = client.readStringUntil('\r'); Serial.println(req); client.flush();

// Match the request int val; if (req.indexOf("/gpio/0") != -1) val = 0; else if (req.indexOf("/gpio/1") != -1) val = 1; else { Serial.println("invalid request"); client.stop(); return; }

// Set GPIO2 according to the request digitalWrite(2, val);

client.flush();

// Prepare the response String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n\r\nGPIO is now "; s += (val)?"high":"low"; s += "\n";

// Send the response to the client client.print(s); delay(1); Serial.println("Client disonnected");

// The client will actually be disconnected // when the function returns and 'client' object is detroyed

Serial.println( ESP.getFreeHeap(),DEC);

}

ivelichkevich commented 5 years ago

The FAQ is in the documentation. Documentation link has been recently made more visible in the ... ... This patch will be proposed to lwIP developpers at some point.

Thanks!

akamming commented 3 years ago

Hi,

i also have this "memory leak" issue on an ESP which is quite busy (constantly updating LED's). the pattern is that sometimes, but not always the heap is decreased by 184 bytes after the call to ESP8266 Webserver handleclient. And some random time (sometimes after a few minutes, sometimes after several hours) a lot of calls to handleclient cause this 184 byte heap decrease, resulting in no more heap memory and a restart of the ESP (due to watchdog or exception)

I applied the "solution in the FaQ" with the tcpcleanup() function. Result is that no more memory is leaked at first, but then again after some random time (again somewhere between a few minutes or a few hours) the handleclient starts "leaking" a lot of memory again... restarting the ESP.

The application is a wordclock, so the restart is very annoying... I know this is an old topic, but hopefully anyone can give me a hint how to fix...

my code can be found here

RobertGnz commented 1 year ago

Hi akamming and fellows, I tried tcpcleanup() and it doesn't work because " while (tcp_tw_pcbs) " never trigger the call to tcp_abort(tcp_tw_pcbs)

Why ? The answer is because the instruction "extern struct tcp_pcb* tcp_tw_pcbs;" does NOT initialise tcp_tw_pcbs to the one used by the Client. It is only a declaration and because it is only a declaration, tcp_tw_pcbs is set to NULL. Consecuently tcp_abort(tcp_tw_pcbs) is never called.

On the following lines of my message I indicate an efficient way to sove the problem. For this I added an API to WiFiClient class. Here is the code:

In WiFiClient.h add the code and comments:

// Api for saving precious heap. // When Client class is used by a Server: Client = Server.available(), sockets in TIME_WAIT remain after // issuing Client.stop by the Server application. // This reduce drastically the heap memory in case of multiple client connections to the server ending // with a Server shutdown and an ESP8266 reboot after some hours because of insufficient heap memory. // This API is provided to free heap memory by mean of closing sockets just before issuing a Client.stop // by the Server. // The Server must use this API just before calling Client.stop // Note: none of the proposed methode e.g. tcpCleanup and tcp_kill_timewait works properly. void abortTimeWait();

In WiFiClient.cpp add the code and comments:

// Api for heap saving. Must be call just before WiFiClient::stop(). void WiFiClient::abortTimeWait() { if (!_client) return; tcp_pcb* p;
p = _client->getPCB(); if (p) tcp_abort(p);
}

With this code you will not be annoyed by sockets in TIME_WAIT state after stopping clients.

I would be gratefull if someone could make a pull request in order to put this API in the GIT repository for use by everybody because I am not familiar with pull requests.

Robert (sorry for my poor English, I am French)

akamming commented 1 year ago

I Fixed my problem by using another led library. The one i used had nointerrupts() builtin, which apparently caused my issue