WPF中BluetoothDevice对象销毁后CPU占用过高问题排查
问题描述
我正在开发一款基于WPF和.NET 8.0的PC配对耳机监控应用。初始无交互空闲状态下CPU占用较低,但创建BluetoothDevice对象并销毁后,空闲状态CPU占用仍居高不下。
通过任务管理器和Windows Assessment and Deployment Kit (Windows ADK)监测:我的PC有7个配对设备,销毁对象后的空闲状态CPU计数约为60000,而初始空闲状态仅约200。看起来对象销毁后仍在被监控,请问如何让空闲状态下的CPU占用保持较低水平?
现有代码
C# 代码(MainWindow.xaml.cs)
public partial class MainWindow : Window { public List<BluetoothDevice> pairedDevice = new List<BluetoothDevice>(); public List<string> IdList; public MainWindow() { InitializeComponent(); IdList = new List<string>() { // 配对耳机的ID }; } private async void Start_Button_Click(object sender, RoutedEventArgs e) { StatusBorder.Background = new SolidColorBrush(Colors.Green); for (int i = 0; i < IdList.Count; i++) { BluetoothDevice temp = await BluetoothDevice.FromIdAsync(IdList[i]); temp.ConnectionStatusChanged += OnBudsConnectionStatusChanged; pairedDevice.Add(temp); Debug.WriteLine($"id: {IdList[i]}, {pairedDevice != null}"); } } private void OnBudsConnectionStatusChanged(BluetoothDevice sender, object args) { Debug.WriteLine($"Connection status changed to : {sender.ConnectionStatus}"); } private async void Stop_Button_Click(object sender, RoutedEventArgs e) { StatusBorder.Background = new SolidColorBrush(Colors.Red); for (int i = 0; i < IdList.Count; i++) { pairedDevice[i].ConnectionStatusChanged -= OnBudsConnectionStatusChanged; pairedDevice[i].Dispose(); pairedDevice[i] = null; } pairedDevice.Clear(); } }
XAML 代码(MainWindow.xaml)
<Window x:Class="BudsWatcherSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:BudsWatcherSample" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <StackPanel VerticalAlignment="Center"> <Border x:Name="StatusBorder" Margin="10" Width="20" Height="5" Background="Black"/> <Button Content="Start" Click="Start_Button_Click" Width="50"/> <Button Content="Stop" Click="Stop_Button_Click" Width="50"/> </StackPanel> </Window>
解决方案
1. 确保事件订阅完全移除
当前代码中事件订阅和移除的是同一个方法,逻辑上没问题,但要避免出现订阅匿名方法或不同委托实例导致的移除失效。如果有异常抛出导致Dispose流程中断,也会影响资源释放,建议加try-catch包裹清理逻辑:
foreach (var device in pairedDevice) { try { device.ConnectionStatusChanged -= OnBudsConnectionStatusChanged; device.Dispose(); } catch (Exception ex) { Debug.WriteLine($"清理设备失败: {ex.Message}"); } }
2. 强制触发垃圾回收
Dispose()仅释放非托管资源,托管对象的回收依赖GC。在清理完所有引用后,手动触发GC可以加速对象回收,避免残留监控逻辑占用CPU:
private async void Stop_Button_Click(object sender, RoutedEventArgs e) { StatusBorder.Background = new SolidColorBrush(Colors.Red); foreach (var device in pairedDevice) { try { device.ConnectionStatusChanged -= OnBudsConnectionStatusChanged; device.Dispose(); } catch (Exception ex) { Debug.WriteLine($"清理设备失败: {ex.Message}"); } } pairedDevice.Clear(); // 强制触发垃圾回收,加速资源释放 GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); }
3. 使用弱事件模式避免内存泄漏
如果担心事件订阅导致BluetoothDevice对象无法被GC回收,可以改用弱事件模式订阅事件,这样即使忘记移除订阅,GC也能正常回收对象:
// 订阅事件时替换为WeakEventManager WeakEventManager<BluetoothDevice, object>.AddHandler(temp, nameof(BluetoothDevice.ConnectionStatusChanged), OnBudsConnectionStatusChanged); // 移除事件时对应使用WeakEventManager WeakEventManager<BluetoothDevice, object>.RemoveHandler(device, nameof(BluetoothDevice.ConnectionStatusChanged), OnBudsConnectionStatusChanged);
4. 检查WinRT对象后台逻辑
部分Windows Runtime对象在Dispose后可能仍有后台线程运行,可查阅BluetoothDevice官方文档,确认是否存在额外需要手动停止的监控方法(如StopMonitoring类接口),确保所有后台监控逻辑完全终止。
内容的提问来源于stack exchange,提问作者Mahfuz
相关产品推荐
相关产品推荐

