文章

WPF 通过 Switch.MS.Internal.EnableWeakEventMemoryImprovements 开关开启弱事件内存优化

默认的 WPF 为了保持行为兼容,没有开启弱事件的内存优化。可以在 WPF 中指定 Switch.MS.Internal.EnableWeakEventMemoryImprovements 和 Switch.MS.Internal.EnableCleanupSchedulingImprovements 开关来让 WPF 运行在 .NET Framework 4.8 或 .NET Core 3.0 以上版本时,自动开启弱事件内存优化。通过这个开关,将会更改部分行为,但是基本上不会有影响,因为影响的都是内存啥时候回收。这些开关和 WPF 应用所使用的开发版本无关,只和 WPF 应用所运行在的设备环境有关,如果在运行的设备上安装了 .NET Framework 4.8 版本,那么自动将会应用上,否则这个开关就和没有写一样
这个功能是在 .NET Framework 4.8 新建的,同时也在 .NET Core 3.0 中。在代码中开启的方法如下

打开 App.xaml.cs 文件,在构造函数添加下面代码

public App()
{
    AppContext.SetSwitch("Switch.MS.Internal.EnableWeakEventMemoryImprovements", true);
    AppContext.SetSwitch("Switch.MS.Internal.EnableCleanupSchedulingImprovements", true);
}

在开启这个功能之后,影响的是 WPF 框架本身,通过开源的 WPF 框架源代码可以了解到,在 src\Microsoft.DotNet.Wpf\src\WindowsBase\MS\Internal\BaseAppContextSwitches.cs 文件有如下定义

/// <summary>
/// Enable/disable various perf and memory improvements related to WeakEvents
/// and the cleanup of WeakReference-dependent data structures
/// </summary>
#region EnableWeakEventMemoryImprovements

internal const string SwitchEnableWeakEventMemoryImprovements = "Switch.MS.Internal.EnableWeakEventMemoryImprovements";
private static int _enableWeakEventMemoryImprovements;

public static bool EnableWeakEventMemoryImprovements
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    get
    {
        return LocalAppContext.GetCachedSwitchValue(SwitchEnableWeakEventMemoryImprovements, ref _enableWeakEventMemoryImprovements);
    }
}

#endregion

这个属性的使用方是在 WPF 中定义的弱事件管理类和相关使用的逻辑,包括

  • src\Microsoft.DotNet.Wpf\src\PresentationFramework\MS\Internal\Data\StaticPropertyChangedEventManager.cs

  • src\Microsoft.DotNet.Wpf\src\PresentationFramework\MS\Internal\Data\ValueChangedEventManager.cs

  • src\Microsoft.DotNet.Wpf\src\WindowsBase\MS\Internal\WeakEventTable.cs

  • src\Microsoft.DotNet.Wpf\src\WindowsBase\System\ComponentModel\PropertyChangedEventManager.cs

  • src\Microsoft.DotNet.Wpf\src\Shared\MS\Internal\ReaderWriterLockWrapper.cs

这几个类都是用来监听各个事件的,如依赖属性本身的通知和 INotifyPropertyChanged 接口的事件等,详细请看 WPF 框架源代码

我的建议是可以在项目中加上此开关,因为阅读完成了 WPF 框架的源代码,没有发现会影响业务功能的逻辑,逻辑上都是性能优化。 未来可能这个属性的默认值会改为 true 表示开启,但当前 .NET 6 下还没有此计划,可以通过以下代码进行判断默认值

// WindowsBase
var assembly = typeof(DependencyObject).Assembly;

// Switch.MS.Internal.EnableWeakEventMemoryImprovements 默认没有开启
var baseAppContextSwitchesType = assembly.GetType("MS.Internal.BaseAppContextSwitches");

var enableWeakEventMemoryImprovementsProperty = baseAppContextSwitchesType.GetProperty("EnableWeakEventMemoryImprovements");

var value = enableWeakEventMemoryImprovementsProperty.GetMethod.Invoke(null, null);

License:  CC BY 4.0