Skip to content

Memory Leak After Disconnect (when acting as a BLE central) #146

Closed
@300bps

Description

@300bps

Issue: When acting as a ble central, there appears to be a persistent memory leak after disconnecting from a device.

Conditions: Circuitpython 7.0.0, mpy=517 library bundle: 7.x-mpy-20211125
Hardware: Feather nrf52840

Description: My application (acting as a central) connects to another adafruit board (Itsy nrf52840) acting as a peripheral, reads some data, and then disconnects. It repeats this process with one or more peripheral boards. I noticed that memory trends monotonically downward, even when explicitly requesting garbage collection, until the application crashes/freezes.

Duplication: I created the following code snippet that demonstrates the issue. Copy the code into code.py on a circuitpython system (see conditions I tested under at top). Replace the address in 'ble_target_address' with the address of a known, connectable device that you can use as the peripheral to connect to. Running the program will repeatedly connect, read services, and disconnect. Each time, it manually requests garbage collection and then prints the free memory. See a snippet of the output of a sample run below the code listing.

import gc, time

from adafruit_ble import BLERadio
from adafruit_ble.services.standard import GenericAccess
import _bleio

# BLE address (little-endian) of a known, connectable ble device
ble_target_address = _bleio.Address(bytes([0x16, 0x08, 0xb0, 0xf4, 0x69, 0xc3]), address_type=_bleio.Address.RANDOM_STATIC)
ble = BLERadio()

while True:
    try:
        conn = None
        try:
            conn = ble.connect(ble_target_address, timeout=2.0)            
            if conn:
                print("<Connect> ", end="")

                # Get services
                try:
                    genericaccess_service = conn[GenericAccess]
                except KeyError as ex:
                    print("<Service not available>")
                    
        except Exception as ex:
            print(ex)
            
        finally:
            # Disconnect
            try:
                if conn:
                    print("<Disconnect>")
                    conn.disconnect()
                    
            except Exception as ex:
                print(ex)

        gc.collect()
        print("gc.mem_free:", gc.mem_free())
        
    except Exception as ex:
        print(ex)

    time.sleep(1)

Sample Run Output:

code.py output:
<Connect> <Disconnect>
gc.mem_free: 116976
<Connect> <Disconnect>
gc.mem_free: 116096
<Connect> <Disconnect>
gc.mem_free: 115200
<Connect> <Disconnect>
gc.mem_free: 114320
<Connect> <Disconnect>
gc.mem_free: 113424
<Connect> <Disconnect>
gc.mem_free: 112544
<Connect> <Disconnect>
gc.mem_free: 111648

.
.
.

<Connect> <Disconnect>
gc.mem_free: 5088
<Connect> <Disconnect>
gc.mem_free: 3888
<Connect> <Disconnect>
gc.mem_free: 3008
<Connect> <Disconnect>
gc.mem_free: 2128
<Connect> <Disconnect>
gc.mem_free: 1248
<Connect> <Disconnect>
gc.mem_free: 368
<Connect> 
<Disconnect>
gc.mem_free: 32

This sample run ended with the device freezing and requiring a hardware reset. The elapsed time from the beginning of the run to the end was approximately 7 minutes and 45 seconds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions