From feb1c57ddee323813e53e3bd20297590cd4b3b74 Mon Sep 17 00:00:00 2001 From: Sebastian Keller Date: Tue, 14 Feb 2023 21:29:43 +0100 Subject: [PATCH] status/network: Fix WirelessNetwork related leaks NetworkManager frequently refreshes the list of available access points. For some reason this often ends up removing some or all access points only to add them back in a later refresh later. With the exception of the currently connected access point, which is never removed. When all access points of a WirelessNetwork have been removed, it gets destroyed by NMWirelessDeviceItem::_removeAccessPoint(). This however does not happen for the currently connected network due to the always present access point. If this network now happens to consist of multiple access points, the "unused" NMAccessPoints will get removed and added in these refreshes, without the WirelessNetwork getting destroyed. Whenever such an unused access point is added, due to the use of signal tracking this leaks the NMAccessPoint and SignalTracker until the WirelessNetwork is destroyed. However when the NMWirelessDeviceItem is destroyed, for example due to suspending, it stops tracking access point changes, ensuring that the condition for the WirelessNetwork being destroyed can not occur anymore. Even with just two access points, such as can be found in 2.4GHz+5GHz home routers this issue leaks hundreds of NMAccessPoints and SignalTrackers per day. As well as a small number of WirelessNetworks which are also kept alive by the SignalTrackers. To fix this disconnect from the access point when it gets removed and destroy all remaining networks when the NMWirelessDeviceItem is destroyed. Part-of: --- js/ui/status/network.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/js/ui/status/network.js b/js/ui/status/network.js index 13f297477..61348883c 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js @@ -876,6 +876,7 @@ const WirelessNetwork = GObject.registerClass({ if (!this._accessPoints.delete(ap)) return false; + ap.disconnectObject(this); this._updateBestAp(); if (wasActive !== this.is_active) @@ -1084,6 +1085,11 @@ const NMWirelessDeviceItem = GObject.registerClass({ this._activeConnectionChanged(); this._availableConnectionsChanged(); this._updateItemsVisibility(); + + this.connect('destroy', () => { + for (const net of this._networkItems.keys()) + net.destroy(); + }); } get icon_name() {