NodeMCU:可用堆大小下降,直到内存不足错误

Posted

技术标签:

【中文标题】NodeMCU:可用堆大小下降,直到内存不足错误【英文标题】:NodeMCU : Available Heaps size falls until out of memory error 【发布时间】:2018-10-09 14:32:47 【问题描述】:

我的 NodeMCU 遇到了一些问题,在接入点模式下运行一个简单的服务器,使用 ESPlorer 在 LUA 中编程。

这是 LUA 脚本:

local SSID = "NodeMCU"
local SSID_PASSWORD = "12345678"

function connect (conn)
   print ("Hello connect")
   conn:on ("receive",
       function (cn, req_data)
           print(req_data)
           print("Available memory :")
           print(node.heap())
           --local query_data = get_http_req (req_data)
           local query_data = 

           cn:send("HTTP/1.1 200 OK\n\n", 
           function()
               cn:close()
               --collectgarbage()
           end)
      end)
end

-- Configure the ESP as a station (client)
wifi.setmode (wifi.SOFTAP)

cfg=
cfg.ssid=SSID
cfg.pwd=SSID_PASSWORD
wifi.ap.config(cfg)

cfg=
cfg.ip="192.168.1.1";
cfg.netmask="255.255.255.0";
cfg.gateway="192.168.1.1";
wifi.ap.setip(cfg)

print("Set up UART config")
uart.setup(1, 921600, 8, uart.PARITY_NONE, uart.STOPBITS_1, 1)

-- Create the httpd server
svr = net.createServer (net.TCP, 30)

-- Server listening on port 80, call connect function if a request is received
svr:listen (80, connect)

一旦这个程序在 NodeMCU 上运行,我通过 WiFi 将我的 PC 连接到 NodeMCU,并使用这段 Java 代码向它发送一些 http POST 请求:

public void sendPost(RGBWPixel[][] LedMatrix) throws Exception 

    HttpURLConnection con = (HttpURLConnection) obj.openConnection();

    System.out.println("Sending post");
    // add reuqest header
    con.setRequestMethod("POST");
    con.setRequestProperty("matrixValues", new String(convertTo1DCharArray(LedMatrix)));
    con.setDoOutput(true);


    DataOutputStream wr = new DataOutputStream(con.getOutputStream());
    wr.flush();
    wr.close();

    con.getResponseCode();


obj是NodeMCU IP地址对应的URLconnection。 matrixValues 对应的 String 长度始终为 2050。

请注意,我将 LUA 脚本缩减为导致问题发生的最小功能。更确切地说,它发生在我有 cn:send() 部分时,但我不知道是否可以在不发送响应的情况下接收和处理请求,因为当我不运行时请求不会发送Java 程序中的 con.getResponseCode()。我是http的初学者,所以我还不了解所有协议。

这是 ESPlorer 中 NodeMCU 端的输出:

> dofile("init.lua");
Set up UART config
> Hello connect
POST / HTTP/1.1
matrixValues: 
Available memory :
38088

Available memory :
37032
Hello connect
POST / HTTP/1.1
matrixValues: 
Available memory :
37688

Available memory :
36664
Hello connect
POST / HTTP/1.1
matrixValues: 
Available memory :
37440

Available memory :
36264

经过几十次迭代,这发生了,NodeMCU 重新启动:

Hello connect
POST / HTTP/1.1
matrixValues: 
Available memory :
4680

Available memory :
3600
E:M 1584
PANIC: unprotected error in call to Lua API (init.lua:19: out of memory)

ets Jan  8 2013,rst cause:2, boot mode:(3,6)

load 0x40100000, len 26704, room 16 
tail 0
chksum 0x0c
load 0x3ffe8000, len 2184, room 8 
tail 0
chksum 0x9a
load 0x3ffe8888, len 136, room 8 
tail 0
chksum 0x44
csum 0x44

第 19 行对应 cn:send() 的行。 我想我在 LUA 脚本中声明一些变量、函数或回调函数时做错了,该堆栈直到没有更多内存...... 另外,我不明白为什么只有 1 个“Hello connect”调用 c​​onn:on 回调函数(其中打印了 node.heap())。就像总是发送第二个 void http 请求......

非常感谢您宝贵的时间和您的潜在帮助,如果您看完这篇文章!

保罗

【问题讨论】:

每个网络帧都会触发receive 事件!因此,如果发送到设备的数据超过 1460 字节(源自以太网帧大小),它将多次触发。您的数据大小为 2050。因此,对于每个 connect 事件,您有 2 个 receive 事件。 【参考方案1】:

sck:send(data, fn) 等价于sck:send(data); sck:on("sent", fn)。 传递给 :on() 的闭包必须直接引用对象 (explanations)。 使用回调函数的第一个参数而不是引用 upvalue。

cn:send(
   "HTTP/1.1 200 OK\n\n", 
   function(s)  -- s here has the same value as cn
      s:close()
      --collectgarbage()
   end
)

【讨论】:

Egor,您知道如何防止此类问题不断涌入吗?我停止计算我给出或多或少相同答案的次数。 @MarcelStör - 是否可以将 luaL_unref(...cb_*_ref)net_delete() 移动到 net_close() 感谢您的帮助,如果这个问题已经回答了很多次,我很抱歉,但是当您不知道问题的确切性质时,很难找到以前的答案。 =/ 但是,我尝试使用您的代码(并使用更短的请求来简化问题),但仍然存在内存泄漏。如果我理解得很好,“conn”、“cn”和“s”在我的脚本中都指的是同一个对象。可能是其他级别的回调有问题? 在我们的文档nodemcu.readthedocs.io/en/latest/en/modules/net/#example_6 中有一个完美的示例(模板)说明如何做到这一点。就假定的泄漏而言,我很确定这不是泄漏。即使使用您的原始代码,您也可以在输出中看到空闲堆不时反弹。那是 GC 清除死内存(例如旧套接字)。这就是为什么如果 MCU 必须快速连续地处理大量请求,您仍然可能会耗尽内存。 GC 释放内存的速度不够快。【参考方案2】:

发送标头:

Connection: close

请求和响应。现代 http 服务器和客户端应用程序的默认设置是保持活动状态。当此标头存在时,另一端将在发送所有数据后显式关闭连接。当连接关闭时,内存被释放。

【讨论】:

以上是关于NodeMCU:可用堆大小下降,直到内存不足错误的主要内容,如果未能解决你的问题,请参考以下文章

即使可用堆内存比使用的大得多,也会出现堆内存不足错误

内存不足错误发生在堆大小高但分配大小低的情况下。为啥?

由于堆大小增加,android中的内存不足错误

Eclipse 堆空间(内存不足错误)

ESP8266 NodeMCU 内存不足

内存不足错误,java堆空间