gpt4 book ai didi

c# - Border.Effect 绑定(bind)泄漏内存但 Border.Background 没有

转载 作者:太空狗 更新时间:2023-10-29 20:39:01 25 4
gpt4 key购买 nike

使用更新的 .NET 4.0,我发现了一个奇怪的内存泄漏,可以通过以下示例代码重现。

  • app.xml 有一些应用程序范围的资源绑定(bind)到 app.xml.cs 中的属性。造成泄漏的资源是一个<DropShadowEffect>谁的Color依赖属性绑定(bind)到 App 对象中的属性。
  • 主窗口有一个启动 LeakWindow 的按钮,其中使用了 app.xml 中定义的资源。
  • 当泄漏窗口关闭时,它不会被垃圾回收。 这个仅当泄漏窗口使用上述 DropShadowEffect 时才会发生资源。不会发生在 SolidColorBrush 上谁的Color也绑定(bind)到相同的来源。

如果有人能告诉我为什么这个泄漏发生在 DropShadowEffect 上,我将不胜感激。但不在 SolidColorBrush 上?

App.xml

<Application x:Class="WpfSimple.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<!--this one make GC unable to collect LeakWindow-->
<DropShadowEffect x:Key="AppDropShadowColor"
Color="{Binding Source={x:Static Application.Current}, Path=DropShadowColor, Mode=OneWay}" />
<!--this one does not leak-->
<SolidColorBrush x:Key="AppBackground"
Color="{Binding Source={x:Static Application.Current}, Path=DropShadowColor, Mode=OneWay}" />
</Application.Resources>
</Application>

App.xml.cs 启动 MainWindow 并实现 INotifyPropertyChanged为属性(property)DropShadowColor .

 public partial class App : Application, INotifyPropertyChanged
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
// start main window
var mainWindow = new MainWindow();
mainWindow.Show();
}

private Color _dropShadowColor = Colors.Blue;
public Color DropShadowColor
{
get { return _dropShadowColor; }
set {
_dropShadowColor = value;
OnPropertyChanged("DropShadowColor");
}
}

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) { handler(this, new PropertyChangedEventArgs(propertyName)); }
}
}

MainWindow.xml 和 MainWindow.xml.cs 有一个创建 LeakWindow 的按钮,如下所示。

var win = new LeakWindow {Owner = this};
win.Show();

还有另一个按钮可以做 GC.Collect() ;

LeakWindow.xml

<Window x:Class="WpfSimple.LeakWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Leak" Height="300" Width="300">
<Grid>
<!--leak-->
<Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" Effect="{StaticResource AppDropShadowColor}"/>

<!--no leak if comment out above and uncomment below-->
<!--<Border Width="200" Height="200" BorderThickness="1" BorderBrush="Black" Background="{StaticResource AppBackground}"/>-->
</Grid>
</Window>

LeakWindow.xml.cs

 public partial class LeakWindow : Window
{
public LeakWindow()
{
InitializeComponent();
}

~LeakWindow()
{
Debug.WriteLine("LeakWindow finalized");
}
}

更新

  • 我的搜索显示这可能与 DynamicResource\StaticResource cause memory leaks .但是那个在 .NET 3.5 的早期就被修补了(kb967328)。还尝试了该线程中提到的 WalkDictionary 方法,但没有帮助。
  • 将绑定(bind)模式更改为OneTime也无济于事。
  • 切换到 .NET 4.5(也已打补丁)并使用 DynamicResource没有帮助。

进一步调查显示泄漏是由 EventHandler 引起的引用自 DropShadowEffectBorder.Effect .可能是由于 DropShadowEffect 中的绑定(bind)而导致的更改通知.
不过,奇怪的是 为什么这只发生在 Border.Effect 上但不在Border.Background

工作场所
添加x:Shared=false<DropShadowEffect>在 app.xml 中可以解决这个问题。我现在可以拥有应用程序范围内定义的资源,但会降低内存效率。

最佳答案

我认为问题是由 DropShadowEffect 附加到可视化树的方式引起的。将 DropShadowEffect 移动到您的控件模板中而不是将其作为资源可能会解决泄漏问题,但是您将失去共享资源...

关于c# - Border.Effect 绑定(bind)泄漏内存但 Border.Background 没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31735010/

25 4 0