又一个模块内存丢失问题

这个问题让我疯了 . 它消耗的时间太多了,我可以帮忙,请!基本上,我使用Get()从我的服务器下载天气数据 . 这很好用 . 我想做的就是在16x2 i2c lcd屏幕上显示它,但是我遇到了'out of memory'问题 . 我已经尝试了社区提供的几个模块,所有人似乎都遇到了同样的问题,所以我确信这个问题与我的代码/调用约定有关 . 我目前正在使用模块lcd.lua,这是Vladimir Dronnikov提供的略有变化 . 并在规定的庄园中称呼它

<pre>
   i2c.setup(0, 3, 4, i2c.SLOW)
   lcd = dofile("lcd.lua")()
</pre>

调用lua脚本充满了印刷语句:

<pre>
    lcd.put(lcd:locate(0, 0),"Mast Temp: ")
</pre>

我的文件结构如下所示

<pre>
    Init.lua -- opportunity to prevent script execution. Calls wifiConnect
    wifiConnect.lua -- connects to wifi and calls dofile(DetServerData())
    GetServerData.lua -- Fetches data and displays on lcd module.
</pre>

当wifiConnect对GetServerData调用dofile时,它通常会被'not enough memory'覆盖,有时脚本会在遇到'out of memory'错误之前运行2到3次 . 然而,我有它跑了8000-9000次,然后跌倒 . (只有一两次 . )如果我允许wifiConnect运行GetFileData,它将停止

<pre>
    PANIC: unprotected error in call to Lua API (not enough memory)
</pre>

加载GetServerData似乎在堆上消耗13816个字节..离开18800.肯定足以运行 . 我尝试过require(getServerData),数字略有不同,结果相同 .

GetServerData如下

--  0 DS18B20_temp_C
     --  1 WindSpeed_kmph
     --  2 WindBearing;
     --  3 WindDir
     --  4 BMP_temp
     --  5 BMP_pressure
      -- BMP_altitude --------------REMOVED
     --  6 DHT22_temperature
     --  7 DHT22_humidity
     -- DH22_dewPoint--------------REMOVED
     -- DHT22_heatIndex--------------REMOVED

    local WDPin = 1
    local LCDscreenPin = 2
    local LCDmaxScreen = 4
    local cycleCount=0
    local WDogLED = false
    local dataTable={} ; i=1
    local connClosed = true
    local LCDpageID = 1

    function GetData()
        if connClosed == true then
            local conn=net.createConnection(net.TCP, 0)
            print("Open connection...")
            WatchDog()
            if conn == nil then
                print("Connection error")
            else
                conn:connect(80,'31.220.16.114')
                connClosed = false
                tmr.alarm(4,3000,0,ResetConn)
                conn:send("GET /test.txt? HTTP/1.1\r\n")
                conn:send("Host:   theoldschool.esy.es\r\n")
                conn:send("Accept: */*\r\n")
                conn:send("User-Agent: Mozilla/4.0 (compatible; esp8266 Lua; Windows NT 5.1)\r\n")
                conn:send("\r\n")
                conn:on("disconnection", function(conn)
                connClosed = true
                WatchDog()
                print("Disconnected...")
                end) -- on:"disconection"
               conn:on("receive",function(conn,payload)
                   cleanData = extractWeatherData(payload)
                   DbugGarbageCollect()
                   fillDataTable(cleanData,'\r\n')
                   for k,v in pairs(dataTable) do print(k,v) end
                       cycleCount = cycleCount +1
                   print(cycleCount)
                   end)-- on recieve
              end-- if conn == nil
       end -- if connClosed
    end--GetData

    function ResetConn()
        print("Stuck")
        connClosed = true
    end -- ResetConn

    function fillDataTable(inputstr, sep)
        local i=0
        for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
            dataTable[i] = str
            i = i + 1
        end--for
     end--splitCmd

    function stripMarkers(str, chrs)
       local s = str:gsub("["..chrs:gsub("%W","%%%1").."]", '')
       return s
    end

    function extractWeatherData (payload)
        local startChar = string.find(payload, '%')
        local s = string.sub(payload, startChar,endChar)
        s = stripMarkers(s, "")
        return s
    end -- extractWeatherData

    function WatchDog()
        if WDogLED == false then
            WDogLED = true
            gpio.write(WDPin, gpio.HIGH)
        else
            WDogLED = false
            gpio.write(WDPin, gpio.LOW)
        end --if
    end--WatchDog

    function DbugGarbageCollect()
        local before = collectgarbage("count")
        collectgarbage()
        print(before - collectgarbage("count"))
        print(node.heap())
    end --DbugGarbageCollect

    function LCDdisplay()
        lcd.clear()
        if LCDpageID == 1 then
            lcd.put(lcd:locate(0, 0),"Mast Temp: ")
            lcd.put(lcd:locate(1, 0),"Shade Tmp: ")
        elseif LCDpageID == 2 then
            lcd.put(lcd:locate(0, 0),"Wind Dir: ")
            lcd.put(lcd:locate(1,0),"Wind Knts: ")
        elseif LCDpageID == 3 then
            lcd.put(lcd:locate(0, 0),"Pressure: ")
            lcd.put(lcd:locate(1, 0),"BMP Temp: ")
        elseif LCDpageID == 4 then
            lcd.put(lcd:locate(0, 0),"DHT Temp: ")
            lcd.put(lcd:locate(1, 0),"Humidity: ")
        else
            lcd.put(lcd:locate(0, 0),"SCREEN ERROR 1")
        end --if
        --updateLCDDisplay()
         collectgarbage()
    end --LCDdisplay

    function updateLCDDisplay()
        if LCDpageID == 1 then
            lcd.put(lcd:locate(0, 11),dataTable[0])
           -- LCDScreenOP.lcdprint(dataTable[0],1,11)
           -- LCDScreenOP.lcdprint(dataTable[7],2,11)
        elseif LCDpageID == 2 then
            --LCDScreenOP.lcdprint(dataTable[2],1,10)
            -- LCDScreenOP.lcdprint(dataTable[3],1,14)
            -- LCDScreenOP.lcdprint(dataTable[1],2,11)
        elseif LCDpageID == 3 then
            -- LCDScreenOP.lcdprint(dataTable[5],1,10)
            -- LCDScreenOP.lcdprint(dataTable[4],2,10)
        elseif LCDpageID == 4 then
            --LCDScreenOP.lcdprint(dataTable[6],1,10)
            -- LCDScreenOP.lcdprint(dataTable[7],2,10)
        else
            --  LCDScreenOP.cls()
            --  LCDScreenOP.cursor(0)
            --  LCDScreenOP.lcdprint("U/D ERROR",1,0)
        end --if
    --   package.loaded.LCDScreenOP = nil
         DbugGarbageCollect()
    end -- updateDisplay

    function LCDScreenChange(level)
        LCDpageID = LCDpageID + 1
        if LCDpageID == LCDmaxScreen + 1 then LCDpageID = 1 end
        LCDdisplay()
    end-- buttonpress

    --============================ CODE ==============================
    i2c.setup(0, 3, 4, i2c.SLOW)
    lcd = dofile("lcd.lua")()
    print ("here")
    gpio.mode(WDPin, gpio.OUTPUT)
    gpio.write(WDPin, gpio.HIGH)
    gpio.mode(LCDscreenPin, gpio.INPUT, gpio.PULLUP)
    DbugGarbageCollect()
    gpio.trig(LCDscreenPin, "down",LCDScreenChange)
    tmr.alarm(2,1500,1,GetData)

并且在加载GetServerData并允许它运行时,esplorer窗口的屏幕抓取看起来像这样

<pre>
   abort = true
        startup aborted
        =node.heap()
        >**32616**
        file.remove("GetServerData.lua");
        file.open("GetServerData.lua","w+");
        w = file.writeline

    -- Above code in here !!

        file.close();
        dofile("GetServerData.lua");
        >not enough memory

        dofile('GetServerData.lua')
        not enough memory
        =node.heap()
        >**18800**
        dofile('GetServerData.lua')
        >not enough memory
</pre>

我们将非常感激地提供任何帮助,并且可以提供任何其他可能有用的信息

非常感谢菲利普

回答(1)

3 years ago

如果您提供Minimal, Complete, and Verifiable example将重现问题( - >最小),那么's quite a lot of code to comb through. It'会更有帮助 .

快速浏览一下就发现了2.5个问题,但可能会有更多问题 .

Closed upvalues

conn:on("receive",function(conn,payload) 泄漏,因为回调参数不应该是 conn 而是其他内容 . 见https://github.com/nodemcu/nodemcu-firmware/issues/194#issuecomment-184817667https://stackoverflow.com/a/37379426/131929

Sending is asynchronous

conn:send 不应该快速连续调用,因为每个调用都是异步的,因此不能保证调用顺序 . 有关详细信息,请参阅net.socket:send文档 .

Consider http module

使用http.get可以帮助您降低代码的复杂性 .