nkolban / esp32-snippets

Sample ESP32 snippets and code fragments
https://leanpub.com/kolban-ESP32
Apache License 2.0
2.34k stars 712 forks source link

BLEClient memory leak #608

Open hirschbrat opened 6 years ago

hirschbrat commented 6 years ago

Hi,

it seems there is a memory problem with the BLE Client: If the BLE Client is initialized in a function the free heap is reduced with every function call resulting in a crash of the ESP32. Up to now I didn't found a way to solve this problem. If I initialize the BLEClient in setup the ESP32 crashes after two connections to the server...

Here is a simple example:

include "BLEDevice.h"

bool connectToServer() { Serial.println("Create Client");
BLEClient* pClient = BLEDevice::createClient(); }

void setup() { Serial.begin(115200); Serial.println("Starting Arduino BLE Client application..."); BLEDevice::init(""); }

void loop() { int freeHeapBefore = ESP.getFreeHeap();

connectToServer();

int freeHeap = ESP.getFreeHeap(); int diff = freeHeap - freeHeapBefore; Serial.print("FreeHeap before: "); Serial.println(freeHeapBefore); Serial.print("FreeHeap after: "); Serial.println(freeHeap); Serial.print("FreeHeap difference: "); Serial.println(diff);
delay(10000); }

Adding the following line at the end of connectToServer() reduces the consumed memory per function call from about 600 to 300 - but still not to zero.

pClient->~BLEClient();

chegewara commented 6 years ago

I am newbie in c++, but what i see is:

Why dont you create client in setup? This way you can reuse client every time you want to connect (multiple connection are not implemented yet anyway).

hirschbrat commented 6 years ago

Hi,

I don't create the client in Setup, because then ESP32 crashes after the second connection to a server. See the examples below:

Example 1 Using local BLE Client works, but free heap is continuously reduced:

#include "BLEDevice.h"

static BLEAddress pServerAddress("c4:7c:8d:66:ac:7a");
static BLEUUID serviceUUID("00001204-0000-1000-8000-00805f9b34fb");
static BLEUUID characteristicUUID("00001a02-0000-1000-8000-00805f9b34fb");

//BLEClient*  pClient;
//BLERemoteService* pRemoteService;
//BLERemoteCharacteristic* pRemoteCharacteristic;

int freeHeap;
int diff;  
int freeHeapBefore;

bool connectToServer( BLEAddress pAddress ) {
    BLEClient* pClient  = BLEDevice::createClient(); 
    Serial.println("--- Connecting to Server ---");    
    if (pClient->connect(pAddress)){
      Serial.println("connected"); 

      BLERemoteService* pRemoteService;
      pRemoteService = pClient->getService(serviceUUID);
      if (pRemoteService == nullptr) {
        Serial.print("Failed to find our service UUID: ");
        Serial.println(serviceUUID.toString().c_str());
      }

      BLERemoteCharacteristic* pRemoteCharacteristic;
      pRemoteCharacteristic = pRemoteService->getCharacteristic(characteristicUUID);

      pClient->disconnect();  

    } else {
      Serial.println("failed"); 
    }

    pClient->~BLEClient();
}

void setup() {
  Serial.begin(115200);

  Serial.println("BLE Client with local BLE objects");
  BLEDevice::init("");

  //pClient  = BLEDevice::createClient(); 
  freeHeapBefore = ESP.getFreeHeap();
}

void loop() {

  connectToServer(pServerAddress);

  freeHeap = ESP.getFreeHeap();
  diff = freeHeap - freeHeapBefore;
  Serial.print("FreeHeap before: ");
  Serial.println(freeHeapBefore);
  Serial.print("FreeHeap after:  ");
  Serial.println(freeHeap);
  Serial.print("FreeHeap difference:  ");
  Serial.println(diff);  
  freeHeapBefore = freeHeap;    
  delay(20000);
}

Example 2 Using global BLE Objects only works for the first connection, after the second connection it crashes (so maybe this example shows the real problem):

#include "BLEDevice.h"

static BLEAddress pServerAddress("c4:7c:8d:66:ac:7a");
static BLEUUID serviceUUID("00001204-0000-1000-8000-00805f9b34fb");
static BLEUUID characteristicUUID("00001a02-0000-1000-8000-00805f9b34fb");

BLEClient*  pClient;
BLERemoteService* pRemoteService;
BLERemoteCharacteristic* pRemoteCharacteristic;

int freeHeap;
int diff;  
int freeHeapBefore;

bool connectToServer( BLEAddress pAddress ) {
    //BLEClient* pClient  = BLEDevice::createClient(); 
    Serial.println("--- Connecting to Server ---");    
    if (pClient->connect(pAddress)){
      Serial.println("connected"); 

      //BLERemoteService* pRemoteService;
      pRemoteService = pClient->getService(serviceUUID);
      if (pRemoteService == nullptr) {
        Serial.print("Failed to find our service UUID: ");
        Serial.println(serviceUUID.toString().c_str());
      }

      //BLERemoteCharacteristic* pRemoteCharacteristic;
      pRemoteCharacteristic = pRemoteService->getCharacteristic(characteristicUUID);

      pClient->disconnect();  

    } else {
      Serial.println("failed"); 
    }

    pClient->~BLEClient();
}

void setup() {
  Serial.begin(115200);

  Serial.println("BLE Client with global BLE objects");
  BLEDevice::init("");

  pClient  = BLEDevice::createClient(); 
  freeHeapBefore = ESP.getFreeHeap();
}

void loop() {

  connectToServer(pServerAddress);

  freeHeap = ESP.getFreeHeap();
  diff = freeHeap - freeHeapBefore;
  Serial.print("FreeHeap before: ");
  Serial.println(freeHeapBefore);
  Serial.print("FreeHeap after:  ");
  Serial.println(freeHeap);
  Serial.print("FreeHeap difference:  ");
  Serial.println(diff);  
  freeHeapBefore = freeHeap;    
  delay(20000);
}

Output after second connection:

--- Connecting to Server --- /Users/ficeto/Desktop/ESP32/ESP32/esp-idf-public/components/freertos/./queue.c:1442 (xQueueGenericReceive)- assert failed! abort() was called at PC 0x40087ac5 on core 1

Backtrace: 0x4008a818:0x3ffd8710 0x4008a917:0x3ffd8730 0x40087ac5:0x3ffd8750 0x400d67ed:0x3ffd8790 0x400d3cae:0x3ffd87d0 0x400d2a0e:0x3ffd8830 0x400d2c94:0x3ffd8880 0x40167f7e:0x3ffd88a0

chegewara commented 6 years ago

You have some issue here: (xQueueGenericReceive)- assert failed! but it has nothing to do with global BLE variables. I am using global variables in product application (not only examples) and i have no issues with reconnecting to peer device. Here is beginning of my file(i cant post more):

#include "BLEDevice.h"

static BLEUUID serviceUUID("e7810a71-73ae-499d-8c15-faa9aef0c3f2");
static BLEUUID    charUUID("bef8d6c9-9c21-4c9e-b632-bd58c1009f9f");

static BLEAddress *pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
BLEClient *pClient;
BLEScan* pBLEScan;
BLERemoteService* pRemoteService;
yuyi1005 commented 6 years ago

I meet the same problem, and I think it is obviously a serious bug. I use the example of BLE_client to reproduce the problem.

Case 1: Delete "doConnect = false;" in the loop() function Then esp32 will reconnect every loop, and it crashes after about 4 loops.

Case2: Move "pClient = BLEDevice::createClient();" into setup(). Then esp32 works only one time, and it crashes on second connection.

This problem is very easy to reproduce, which takes only 5 minutes.

gourryinverse commented 6 years ago

for those struggling with the second client connection crashing the server:

https://github.com/nkolban/esp32-snippets/commit/984a7aba4253fb29e25f2022e909f17adc447d22#diff-6b48b04d9f9202e7dc8114b588e968ba

this is the issue, update your library