Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak on Linux with repeated device connections #252

Open
jasday opened this issue Mar 19, 2024 · 2 comments
Open

Memory leak on Linux with repeated device connections #252

jasday opened this issue Mar 19, 2024 · 2 comments

Comments

@jasday
Copy link

jasday commented Mar 19, 2024

Expanding on the example heartbeat-monitor, I'm getting what appears to be a memory leak when re-connecting to a device after the first connection.

An example use case:

  • BLE Central starts adapter scan, awaits for device to advertise accepted service
  • Device is found, central connects to device and enables notifications
  • Central receives data, then disconnects device (at this point device could already have left range or been turned off)
  • Upon device re-discovery, central connects again to device, and from this point onwards an increased memory usage is noted (increases by ~2mb every 10 seconds or so, with no hard limit - has reached at least 500mb).

Example code, edited slightly from the source:

func (o *Bluetooth) Start() error {
        println("enabling")

	// Enable BLE interface.
	must("enable BLE stack", adapter.Enable())

	// Start scanning.
	println("scanning...")
        // Added a loop so we can start the scan again once we've finished with the current device
        for {
		ch := make(chan bluetooth.ScanResult, 1)

		// Start scanning.
		println("scanning...")
		err = adapter.Scan(func(adapter *bluetooth.Adapter, result bluetooth.ScanResult) {
			println("found device:", result.Address.String(), result.RSSI, result.LocalName())
                        // Using a health thermometer service as a test here, can be swapped out with anything else
			if result.AdvertisementPayload.HasServiceUUID(bluetooth.ServiceUUIDHealthThermometer) {
				adapter.StopScan()
				ch <- result
			}
		})
                var device *bluetooth.Device

		select {
		case result := <-ch:
			device, err := adapter.Connect(result.Address, bluetooth.ConnectionParams{})
			if err != nil {
				println(err.Error())
				return err
			}

			println("connected to ", result.Address.String())
			// Handle some logic here on the device
			println("Disconnected")
			device.Disconnect()
		}
	}

}

Go version: 1.22.1
tinygo/x/bluetooth: 0.8.0

Compiling onto Linux Arm64, with a IW416 SOC

Am I doing anything wrong based on the example code? The only real difference here is the added loop, which (hopefully) allows for scanning and connecting to different devices. (I need to be able to connect to multiple devices with various different services at unknown times, so this is just attempting to get the basics working, so I need the ability to restart the scan once the operation on the current device is finished)

Any ideas?

@asteria-jacky
Copy link

asteria-jacky commented Mar 22, 2024

I think the example code is good, instead there could be a problem in gap_linux.go. I see the number of goroutines keep incrasing together with memory usage, even after trying to connect once.

I can't see anywhere (*device.Device1).UnwatchProperties get called while there is (*device.Device1)WatchProperties. This can make underlying dbus signal channel not get unregistered, then result in leaking a goroutine for every single deffered undelivered signal from dbus.

bluetooth/gap_linux.go

Lines 326 to 331 in d0c7887

func (d *Device) watchForConnect() error {
var err error
d.propchanged, err = d.device.WatchProperties()
if err != nil {
return err
}

I forked and added a defer d.device.UnwatchProperties(d.propchanged) and it seems okay so far.

They are trying to remove the dependency on muka/bluetooth, so I doubt this will be fixed.

@jasday
Copy link
Author

jasday commented Apr 2, 2024

This seems to have been fixed in the latest v0.9.0 - When simply connecting to a device and disconnecting the memory no longer increases and will remain fairly stable. There is however increasing memory usage when connecting to a device and enabling notifications as mentioned in #260.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants