ESP8266 NodeMCU Running Out of Heap Memory

There was a problem in the NodeMCU docs with the socket:send example you seem to have based your implementation on. We discussed it and I fixed it.

An improved version of your code is this:

gpio.mode(3, gpio.OUTPUT)
srv = net.createServer(net.TCP, 28800)
print("Server created... \n")
local pinState = 0
srv:listen(80, function(conn)
    conn:on("receive", function(sck, request)
        local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
        if (method == nil) then
            _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
        end
        local message = {}
        message[#message + 1] = "HTTP/1.1 200 OK\r\n"
        message[#message + 1] = "Content-Type: text/html\r\n\r\n"
        print("Method:" .. method);
        if (method == "POST") then
            message[#message + 1] = "POST request successfully received\r\n"
            if (pinState == 0) then
                gpio.write(3, gpio.HIGH)
                pinState = 1
                print("LED ON")
            elseif (pinState == 1) then
                gpio.write(3, gpio.LOW)
                pinState = 0
                print("LED OFF")
            end
        elseif (method == "GET") then
            message[#message + 1] = "LED STATE=" .. tostring(pinState) .. "\r\n"
        end
        local function send(sk)
            if #message > 0 then
                sk:send(table.remove(message, 1))
            else
                sk:close()
                message = nil
                print("Heap Available:" .. node.heap())
            end
        end
        sck:on("sent", send)
        send(sck)
    end)
end)

I removed some duplicated code wrt populating message and I also remove the “resetting” and GC code at the end (no longer relevant). The real issue though was with closed upvalues in the callback functions.

Each of your callback functions should use its own copy of the passed socket instance rather referencing the one of a wrapping callback function.

  • On line 5 srv:listen(80, function(conn) the socket variable in the callback is conn.
  • On line 6 there’s another callback function which receives a socket, this time called sck. It should be referenced within that function as sck (sck:on() and send(sck)).
  • The socket:on("sent") callback itself receives a/the socket instance. Your original send() function didn’t not use that though and used conn instead. So, I added sk and use this one exclusively within send().

Leave a Comment