使用ItemsControl Silverlight 4内存泄漏

时间:2010-08-20 09:30:36

标签: silverlight memory-leaks itemscontrol

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

剥离出来,似乎问题是由ItemsControl引起的,其中自定义DataTemplate绑定到实现INotifyPropertyChanged接口的IEnumerable对象集合。

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

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

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

编辑: 事实证明,泄漏发生在这种情况下:

  • 通过RIA服务上下文加载实体,并将它们的集合存储在viewmodel
  • 的属性中
  • 将带有自定义数据模板的listview绑定到具有entites集合的属性
  • 通过RIA服务上下文刷新entites

虽然实体得到了刷新,但在视图中可以看到,内存消耗正在上升。

如果没有绑定,刷新实体不会占用更多内存(可能会因为GC完成其工作而最终返回内存消耗级别)。

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

似乎问题与RIA服务有关。

如果您愿意,我可以提供一个显示问题的简单项目。

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

3 个答案:

答案 0 :(得分:2)

<强>更新

Silverlight 4服务版本修复内存泄漏: http://timheuer.com/blog/archive/2010/09/01/silverlight-service-release-september-2010-gdr1.aspx

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

这是我一直关注的主题:

用户“heuertk”是Microsoft Silverlight Developer ....他解释了问题和修复的状态...

http://forums.silverlight.net/forums/t/171739.aspx

答案 1 :(得分:1)

据我了解,此特定问题是Silverlight 4本身的一个错误。但是,你说你遇到了另一个内存泄漏。你确定那个是否与Caliburn.Micro有关,如果是的话,你有没有在项目论坛上发布过它?如果故障在CM中,我想尝试修复它。感谢。

答案 2 :(得分:1)

嘿,我正在玩你的解决方案,我想出了这个解决方法,它工作得很好,基本上你将你的DataSrc类更改为以下,唯一的问题是如何在Ria Services实体上应用类似的东西。我已经在使用T4来调整代码生成(对于小事情)但是我不确定我是否可以在中间强制这样的东西。另外,我想问一下,您是否在样本申请中报告了您的问题?额外的报告从未受到伤害:)

    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;
    }
}