As the title says... Chat on...

User avatar
By marcelstoer
#64514
limbo wrote:I know this is a known issue.


Where did you pick that up? It's neither a known issue nor were you quoting an actual example from our documentation IIRC. The closest we have is with http://nodemcu.readthedocs.io/en/latest ... etsocketon

Code: Select allsrv = net.createConnection(net.TCP, 0)
srv:on("receive", function(sck, c) print(c) end)
srv:on("connection", function(sck, c)
  -- Wait for connection before sending.
  sck:send("GET /get HTTP/1.1\r\nHost: httpbin.org\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n")
end)
srv:connect(80,"httpbin.org")


If you access the `srv` variable within a `srv.on` callback function (as with your example) you're actually creating a memory leak. Some explanation is here: http://stackoverflow.com/a/37379426/131929.

What you're likely seeing (besides the above) is too many open sockets in TIME_WAIT status i.e. not yet closed. https://github.com/nodemcu/nodemcu-firmware/pull/1838 reduced the number of seconds such sockets should be kept around. You might also try to replace `Connection: keep-alive` with `Connection: close` and see how the server reacts.
User avatar
By BrettJ123
#65725
If you access the `srv` variable within a `srv.on` callback function (as with your example) you're actually creating a memory leak. - See more at: posting.php?mode=reply&f=24&t=14370#sthash.7gLdOrHy.dpuf

If accessing "srv" variable with ":on" callback function will create a memory leak, then what is the proper way to open a client connection, send or recieve data and close the connection without leaking?

I am trying to create a simple program the monitors a GPIO pin for button press, and when it's pressed, connect to a server, send a message, and disconnect. Then wait for another button press. No matter what I have tried so far, I am always leaking memory.

Here is my current code

Code: Select alldo
    local pin = 1
    local function pin1cb(l, t)
        gpio.trig(pin, nil) --disable trigger callback for debounce
        local debouncecb = function ()
            gpio.trig(pin, "down", pin1cb) --enable trigger callback from debounce
            print("Button Pressed Out "..node.heap())
        end
        local srv = net.createConnection(net.TCP, 0)
        srv:on("connection", function(s) s:send("Hello World\r\n") end)
        srv:on("sent", function(s) s:close() end)
        srv:connect(10000,"192.168.1.100")
        tmr.create():alarm(
            500,
            tmr.ALARM_SINGLE,
            debouncecb --debounce callback
        )
        print("\nButton Pressed In "..node.heap())
    end
   
    gpio.mode(pin, gpio.INT, gpio.PULLUP)
    gpio.trig(pin, "down", pin1cb) --initial enable trigger callback
end

Here is the output from the console

Code: Select allButton Pressed In 40488
Button Pressed Out 41056

Button Pressed In 40768
Button Pressed Out 40848

Button Pressed In 40584
Button Pressed Out 40664

Button Pressed In 39632
Button Pressed Out 39712

Button Pressed In 39440
Button Pressed Out 39520

Button Pressed In 39256
Button Pressed Out 39336


Each time the button triggers, the heap drops by about 200 bytes. This will continue until heap is exhausted.
User avatar
By BrettJ123
#65753 UPDATE
It looks like my issue was due to TCP_WAIT sockets as well. I restructured my code a little bit, and I changed my testing process. Now, I hit the button, and wait several minutes before hitting the button again (which will be how the device will work in real world use case). Now, I see the heap staying at the same size between each button press. If I hit the button multiple times, I do see the heap size decrease with each button press. I assume this is because each time I press the button, I create a new socket, which then remains in TIME_WAIT for a period. If I wait several minutes, and hit the button again, the heap jumps back up.

For the record, here is the most recent version of my code I am testing
Code: Select alllocal pin = 1
local function pin1cb(l, t)
    gpio.trig(pin, nil)
    local srv = net.createConnection(net.TCP, 0)
    srv:on("connection", function(s)
        s:send("Hello World\r\n")
    end)
    srv:on("sent", function(s)
        s:close()
        tmr.create():alarm(500, tmr.ALARM_SINGLE, function ()
            gpio.trig(pin, "down", pin1cb)
            print("Button Pressed Out "..node.heap())
        end)
    end)
    srv:connect(10000,"192.168.1.100")
    print("\nButton Pressed In "..node.heap())
end
gpio.mode(pin, gpio.INT, gpio.PULLUP)
gpio.trig(pin, "down", pin1cb)

And here is the output spread out of a 12 hour test period
Code: Select allButton Pressed In 39248
Button Pressed Out 39312

Button Pressed In 39264
Button Pressed Out 39512

Button Pressed In 39448
Button Pressed Out 39512

Button Pressed In 39448
Button Pressed Out 39512

Button Pressed In 39264
Button Pressed Out 39512

Button Pressed In 39264
Button Pressed Out 39328

Button Pressed In 39264
Button Pressed Out 39512

Button Pressed In 39448
Button Pressed Out 39720

Button Pressed In 39448
Button Pressed Out 39720

Button Pressed In 39184
Button Pressed Out 39720

The first few test were performed after other testing, so the out heap stayed around 39512. The last few log enteries were performed at least 10 minutes apart and the last being 10 hours apart, and the board seems to have stablized around 39720.

So in my case, there does not appear to be a leak after all. I just needed to wait for the sockets to full close before the heap is released.
User avatar
By marcelstoer
#65815
BrettJ123 wrote:It looks like my issue was due to TCP_WAIT sockets as well.


As you see in the issue I referenced TIME_WAIT is going to be significantly reduced with the next release. Furthermore, if you communicate over HTTP you can send a "Connection: close" header to instruct the client to hang up.

Code: Select alls:send("HTTP/1.0 200 OK\r\nContent-type: text/html\r\nConnection: close\r\n\r\nHello World")