在我们基于Caliburn.Micro构建的SL4应用程序中,我们遇到了(另一个)内存泄漏。
剥离出来,似乎问题是由ItemsControl引起的,其中自定义DataTemplate绑定到实现INotifyPropertyChanged接口的IEnumerable对象集合。
当源集合被更改(另一个集合被分配给ItemsControl的ItemsSource绑定的ViewModel属性)时,原始集合和绑定的DataTemplates中的entites不会被垃圾回收。虽然NotifyPropertyChanged的事件处理似乎是通过WeakReference在内部完成的,但就像SL保留了对这些对象的另一个引用。因此,每次从服务器刷新数据时,内存消耗都会增加。
你知道如何解决这个问题吗? 我真的不明白SL4中怎么会发生这种错误!
一些实验表明调用ItemsControl.Items.Clear()可能有所帮助。任何提示如何在每次更改ItemsSource时简单地调用它?我唯一想到的就是覆盖ItemsSourceProperty并在那里添加一个处理程序。
编辑: 事实证明,泄漏发生在这种情况下:
虽然实体得到了刷新,但在视图中可以看到,内存消耗正在上升。
如果没有绑定,刷新实体不会占用更多内存(可能会因为GC完成其工作而最终返回内存消耗级别)。
如果清除上下文或只是创建一个新的上下文,最终也会收集内存。
似乎问题与RIA服务有关。
如果您愿意,我可以提供一个显示问题的简单项目。
更新:内存泄漏似乎是由INotifyDataErrorInfo引起的。阅读here。
答案 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 ....他解释了问题和修复的状态...
答案 1 :(得分:1)
据我了解,此特定问题是Silverlight 4本身的一个错误。但是,你说你遇到了另一个内存泄漏。你确定那个是否与Caliburn.Micro有关,如果是的话,你有没有在项目论坛上发布过它?如果故障在CM中,我想尝试修复它。感谢。
答案 2 :(得分:1)
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;
}
}