首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Border.Effect绑定泄漏内存,但Border.Background没有

Border.Effect绑定泄漏内存,但Border.Background没有
EN

Stack Overflow用户
提问于 2015-07-30 22:15:59
回答 2查看 462关注 0票数 7

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

  • app.xml有一些应用程序范围的资源,这些资源绑定到app.xml.cs中的属性。创建泄漏的资源是一个<DropShadowEffect>,其Color依赖属性绑定到App中的一个属性。
  • 主窗口有一个按钮来启动LeakWindow,在其中使用app.xml中定义的资源。
  • 当泄漏窗口关闭时,它不会被垃圾收集。只有当泄漏窗口使用上面提到的DropShadowEffect 资源时,才会发生这种情况。不发生在SolidColorBrush 上,其 Color 也绑定到相同的源。

非常感谢有人能告诉我为什么这个泄漏发生在DropShadowEffect上,而不是在SolidColorBrush上。

App.xml

代码语言:javascript
复制
<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并为属性DropShadowColor实现INotifyPropertyChanged

代码语言:javascript
复制
 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,如下所示。

代码语言:javascript
复制
var win = new LeakWindow {Owner = this};
win.Show();

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

LeakWindow.xml

代码语言:javascript
复制
<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

代码语言:javascript
复制
 public partial class LeakWindow : Window
    {
        public LeakWindow()
        {
            InitializeComponent();
        }    

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

更新

  • 我的搜索显示这可能与动态资源\静态资源导致内存泄漏有关。但这一问题在.NET 3.5(kb967328)中得到了早期修补。也尝试了这个线程中提到的WalkDictionary方法,但是没有帮助。
  • 将绑定模式更改为OneTime也无济于事。
  • 切换到.NET 4.5 (到目前为止也进行了修补)并使用DynamicResource没有帮助。

进一步的调查表明,泄漏是由EventHandler引用从DropShadowEffectBorder.Effect造成的。可能是由于DropShadowEffect中的绑定导致的更改通知。

然而,奇怪的是,为什么这只发生在Border.Effect Border.Background**?**上,而不发生在上。

工作站

x:Shared=false添加到app.xml中的<DropShadowEffect>可以解决这一问题。我现在可以拥有应用程序范围的定义资源,但失去了内存效率。

EN

回答 2

Stack Overflow用户

发布于 2015-07-31 08:59:19

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

票数 2
EN

Stack Overflow用户

发布于 2015-07-31 12:55:49

代码语言:javascript
复制
        <Controls:MetroWindow x:Class="WpfApplication.Window"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" 
    ShowMaxRestoreButton="False" 
        ResizeMode="NoResize" ShowMinButton="False" 
        EnableDWMDropShadow="True" WindowStartupLocation="CenterScreen" Name="Window" 
Height="400" Width="567">

您可以尝试导入mah应用程序,它有带有一行EnableDWMDropShadow="True“行的阴影窗口。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31735010

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档