You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 18:23:18