From af6091b493a0dcac4794f2400c14f780a54bfefd Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 7 Jun 2023 17:10:32 +0200 Subject: [PATCH] fixing some memory leaks * audio_reactive.h: catch memory errors from WiFiUDP * udp: explicitly flush unused receive buffers. * wled.cpp: additional debug info about "largest available block" * FX_fcn.cpp: free _globalLeds before running purgeSegments(). --- usermods/audioreactive/audio_reactive.h | 23 +++++++++++++++++++---- wled00/FX_fcn.cpp | 2 +- wled00/udp.cpp | 12 ++++++------ wled00/wled.cpp | 6 ++++-- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 188d1b35..74dd692a 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1378,9 +1378,10 @@ class AudioReactive : public Usermod { transmitData.FFT_Magnitude = my_magnitude; transmitData.FFT_MajorPeak = FFT_MajorPeak; - fftUdp.beginMulticastPacket(); - fftUdp.write(reinterpret_cast(&transmitData), sizeof(transmitData)); - fftUdp.endPacket(); + if (fftUdp.beginMulticastPacket() != 0) { // beginMulticastPacket returns 0 in case of error + fftUdp.write(reinterpret_cast(&transmitData), sizeof(transmitData)); + fftUdp.endPacket(); + } return; } // transmitAudioData() @@ -1448,7 +1449,21 @@ class AudioReactive : public Usermod { if (!udpSyncConnected) return false; bool haveFreshData = false; - size_t packetSize = fftUdp.parsePacket(); + size_t packetSize = 0; + // WLEDMM use exception handler to catch out-of-memory errors + #if __cpp_exceptions + try{ + packetSize = fftUdp.parsePacket(); + } catch(...) { + packetSize = 0; // low heap memory -> discard packet. + fftUdp.flush(); + DEBUG_PRINTLN(F("receiveAudioData: parsePacket out of memory exception caught!")); + USER_FLUSH(); + } + #else + packetSize = fftUdp.parsePacket(); + #endif + if ((packetSize > 0) && ((packetSize < 5) || (packetSize > UDPSOUND_MAX_PACKET))) fftUdp.flush(); // discard invalid packets (too small or too big) if ((packetSize > 5) && (packetSize <= UDPSOUND_MAX_PACKET)) { static uint8_t fftUdpBuffer[UDPSOUND_MAX_PACKET+1] = { 0 }; // static buffer for receiving, to reuse the same memory and avoid heap fragmentation diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 8296d3ff..0e7b3f81 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1494,9 +1494,9 @@ void WS2812FX::finalizeInit(void) //initialize leds array. TBD: realloc if nr of leds change if (Segment::_globalLeds) { - purgeSegments(true); free(Segment::_globalLeds); Segment::_globalLeds = nullptr; + purgeSegments(true); // WLEDMM moved here, because it seems to improve stability. } if (useLedsArray && getLengthTotal()>0) { // WLEDMM avoid malloc(0) size_t arrSize = sizeof(CRGB) * getLengthTotal(); diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 1ad218da..a320f11b 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -243,14 +243,14 @@ void handleNotifications() if (!packetSize && udpRgbConnected) { packetSize = rgbUdp.parsePacket(); if (packetSize) { - if (!receiveDirect) return; - if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) return; + if (!receiveDirect) {rgbUdp.flush(); notifierUdp.flush(); notifier2Udp.flush(); return;} + if (packetSize > UDP_IN_MAXSIZE || packetSize < 3) {rgbUdp.flush(); notifierUdp.flush(); notifier2Udp.flush(); return;} realtimeIP = rgbUdp.remoteIP(); DEBUG_PRINTLN(rgbUdp.remoteIP()); uint8_t lbuf[packetSize]; rgbUdp.read(lbuf, packetSize); realtimeLock(realtimeTimeoutMs, REALTIME_MODE_HYPERION); - if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) return; + if (realtimeOverride && !(realtimeMode && useMainSegmentOnly)) {notifierUdp.flush(); notifier2Udp.flush(); return;} uint16_t id = 0; uint16_t totalLen = strip.getLengthTotal(); for (size_t i = 0; i < packetSize -2; i += 3) @@ -263,12 +263,12 @@ void handleNotifications() } } - if (!(receiveNotifications || receiveDirect)) return; + if (!(receiveNotifications || receiveDirect)) {notifierUdp.flush(); notifier2Udp.flush(); return;} localIP = Network.localIP(); //notifier and UDP realtime - if (!packetSize || packetSize > UDP_IN_MAXSIZE) return; - if (!isSupp && notifierUdp.remoteIP() == localIP) return; //don't process broadcasts we send ourselves + if (!packetSize || packetSize > UDP_IN_MAXSIZE) {notifierUdp.flush(); notifier2Udp.flush(); return;} + if (!isSupp && notifierUdp.remoteIP() == localIP) {notifierUdp.flush(); notifier2Udp.flush(); return;}; //don't process broadcasts we send ourselves uint8_t udpIn[packetSize +1]; uint16_t len; diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 98ada737..20c0da20 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -278,14 +278,16 @@ void WLED::loop() DEBUG_PRINT(F("Name: ")); DEBUG_PRINTLN(serverDescription); DEBUG_PRINT(F("Runtime: ")); DEBUG_PRINTLN(millis()); DEBUG_PRINT(F("Unix time: ")); toki.printTime(toki.getTime()); - DEBUG_PRINT(F("Free heap: ")); DEBUG_PRINTLN(ESP.getFreeHeap()); + DEBUG_PRINT(F("Free heap : ")); DEBUG_PRINTLN(ESP.getFreeHeap()); #ifdef ARDUINO_ARCH_ESP32 + DEBUG_PRINT(F("Avail heap: ")); DEBUG_PRINTLN(ESP.getMaxAllocHeap()); DEBUG_PRINTF("%s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM #endif #if defined(ARDUINO_ARCH_ESP32) && defined(BOARD_HAS_PSRAM) if (psramFound()) { //DEBUG_PRINT(F("Total PSRAM: ")); DEBUG_PRINT(ESP.getPsramSize()/1024); DEBUG_PRINTLN("kB"); - DEBUG_PRINT(F("Free PSRAM: ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Free PSRAM : ")); DEBUG_PRINT(ESP.getFreePsram()/1024); DEBUG_PRINTLN("kB"); + DEBUG_PRINT(F("Avail PSRAM: ")); DEBUG_PRINT(ESP.:getMaxAllocPsram()/1024); DEBUG_PRINTLN("kB"); DEBUG_PRINT(F("PSRAM in use:")); DEBUG_PRINT(ESP.getPsramSize() - ESP.getFreePsram()); DEBUG_PRINTLN(F(" Bytes")); } else {