Silverlight 4内存泄漏与ItemsControl

Silverlight 4内存泄漏与ItemsControl,silverlight,memory-leaks,itemscontrol,Silverlight,Memory Leaks,Itemscontrol,在基于Caliburn.Micro构建的SL4应用程序中,我们遇到了(另一个)内存泄漏 简单地说,问题似乎是由ItemsControl引起的,它将自定义DataTemplate绑定到实现INotifyPropertyChanged接口的IEnumerable对象集合 更改源集合时(将另一个集合分配给ItemsControl的ItemsSource绑定到的ViewModel属性),原始集合和绑定数据模板中的实体不会被垃圾收集。尽管NotifyPropertyChanged的事件处理似乎是通过Wea

在基于Caliburn.Micro构建的SL4应用程序中,我们遇到了(另一个)内存泄漏

简单地说,问题似乎是由ItemsControl引起的,它将自定义DataTemplate绑定到实现INotifyPropertyChanged接口的IEnumerable对象集合

更改源集合时(将另一个集合分配给ItemsControl的ItemsSource绑定到的ViewModel属性),原始集合和绑定数据模板中的实体不会被垃圾收集。尽管NotifyPropertyChanged的事件处理似乎是通过WeakReference在内部完成的,但这就像SL保留了对这些对象的另一个引用一样。因此,每次我们从服务器刷新数据时,内存消耗都会增加

你知道如何解决这个问题吗? 我真的不明白SL4怎么会出现这种错误

一些实验表明,调用ItemsControl.Items.Clear()可能会有所帮助。有没有提示如何在每次更改ItemsSource时简单地调用它?我唯一想到的是重写ItemsSourceProperty并在那里添加一个处理程序

编辑: 结果表明,泄漏发生在这种情况下:

  • 通过RIA服务上下文加载实体,并将它们的集合存储在viewmodel的属性中
  • 将具有自定义数据模板的listview绑定到具有Entite集合的属性
  • 通过RIA服务上下文刷新实体
发生的情况是,尽管实体被刷新(可以在视图中看到),但内存消耗正在增加

如果没有绑定,刷新实体不会消耗更多内存(可能会消耗更多内存,但随着GC完成其工作,内存消耗水平最终会返回)

如果清除上下文或只是创建一个新上下文,那么最终也会收集内存

问题似乎与RIA服务有关

我可以提供一个简单的项目,显示问题,如果你想


更新:内存泄漏似乎是由INotifyDataErrorInfo引起的。阅读。

更新:

Silverlight 4服务版本修复内存泄漏:

Silverlight 4已知数据模板存在内存泄漏问题。目前正在测试的方式有一个修正

以下是我一直遵循的一条线索:

用户“heuertk”是Microsoft Silverlight开发人员…他解释了问题和修复状态


据我所知,这个问题是Silverlight 4本身的一个bug。但是,您说您遇到了另一个内存泄漏。你确定那件事是否与Caliburn.Micro有关吗?如果是的话,你是否在项目论坛上发布过?如果故障在CM中,我想尝试修复它。谢谢。

嘿,我对您的解决方案进行了一些研究,我提出了这个解决方案,效果很好,基本上您将DataSrc类更改为以下内容,唯一的问题是如何在Ria服务实体上应用类似的内容。我已经使用T4来调整代码生成(对于次要的事情),但我不确定是否可以在两者之间强制执行类似的操作。另外,我想问一下,您是否用示例应用程序报告了您的问题?额外的报告不会有什么坏处:)

公共类数据rc:INotifyDataErrorInfo
{
公共字符串名称{get;set;}
公共IEnumerable GetErrors(字符串propertyName)
{
屈服断裂;
}
public void InvokeEvent()
{
_OneEvent(这是新的DataErrorsChangedEventArgs(“名称”);
}
私人软弱者被改变(你软弱者被改变);;
公共事件事件处理程序错误更改
{
添加
{ 
_weakinkerrorChanged=新的weakinkerrorChanged(此);
_weaklinkorchanged.ErrorsChanged+=值;
}
删除{u weakinkerrorchanged.ErrorsChanged-=value;}
}
公共布尔错误
{
获取{return false;}
}
}
内部类的薄弱环节在TInstance:class处被更改
{
私有只读WeakReference\u weakInstance;
公共事件事件处理程序错误更改;
公共弱点已更改(TInstance实例)
{
if(实例==null)
{
抛出新的ArgumentNullException(“实例”);
}
_weakInstance=新的WeakReference(实例);
}
public void OneEvent(TSource源、DataErrorsChangedEventArgs事件args)
{
var target=_weakInstance.target作为TInstance;
如果(目标!=null)
{
if(ErrorsChanged!=null)
ErrorsChanged(目标、事件参数);
}
其他的
ErrorsChanged=null;
}
}

感谢您提醒我这个问题!你知道它是否发生在WPF?还不知道。但我将尝试为WPF和SL准备一个简单的演示来重现这个问题,我们拭目以待。你也有同样的问题吗?到目前为止,似乎连RIA都可能在某种程度上影响了这个问题……只是想确认一下:您在发布模式下测试这个问题,没有附加调试器,对吗?@Kent,这不重要。释放或调试模式,无论是否连接调试器,泄漏仍然存在。嗨,Rob。嗯,虽然这不是最新版本GDR1解决的众所周知的SL4错误,但它似乎与RIA服务有关。请参阅更新的问题。无论如何,非常感谢您的Caliburn Micro,它真的很棒!如果泄漏是由CM引起的,我会首先尝试自己修复,然后将修复方法发送给您:-)。嗨,Rob。我们最终跟踪了内存泄漏-它不是由C.Micro引起的,而是由SL本身引起的(INotifyDataErrorInfo)。我在博客上写过:
    public class DataSrc  :INotifyDataErrorInfo
{
    public string Name { get; set; }

    public IEnumerable GetErrors(string propertyName)
    {
        yield break;
    }

    public void InvokeEvent()
    {
        _weakLinkErrorChanged.OnEvent(this, new DataErrorsChangedEventArgs("Name"));
    }

    private WeakLinkErrorChanged<DataSrc, object> _weakLinkErrorChanged;

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged
    {
        add 
        { 
             _weakLinkErrorChanged=new WeakLinkErrorChanged<DataSrc, object>(this);
            _weakLinkErrorChanged.ErrorsChanged += value;
        }

        remove { _weakLinkErrorChanged.ErrorsChanged -= value; }
    }

    public bool HasErrors
    {
        get { return false; }
    }
}


internal class WeakLinkErrorChanged<TInstance, TSource> where TInstance : class
{

    private readonly WeakReference _weakInstance;

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

    public WeakLinkErrorChanged(TInstance instance)
    {
        if (instance == null)
        {
            throw new ArgumentNullException("instance");
        }

        _weakInstance = new WeakReference(instance);
    }

    public void OnEvent(TSource source, DataErrorsChangedEventArgs eventArgs)
    {
        var target = _weakInstance.Target as TInstance;

        if (target != null)
        {
            if(ErrorsChanged!=null)
                ErrorsChanged(target, eventArgs);
        }
        else
            ErrorsChanged = null;
    }
}