Утечка памяти в Silverlight 4 с ItemsControl - PullRequest
2 голосов
/ 20 августа 2010

В нашем приложении SL4, построенном на Caliburn.Micro, мы столкнулись с (еще одной) утечкой памяти.

Похоже, что проблема вызвана ItemsControl с пользовательским DataTemplate, связанным с коллекцией объектов IEnumerable, которые реализуют интерфейс INotifyPropertyChanged.

Когда исходная коллекция изменяется (другая коллекция назначается свойству ViewModel, к которому привязан ItemsSource элемента ItemsControl), объекты в исходной коллекции и связанные шаблоны данных не собираются сборщиком мусора. Хотя обработка событий NotifyPropertyChanged, по-видимому, выполняется внутренне через WeakReference, похоже, что SL сохраняет другую ссылку на эти объекты. Поэтому каждый раз, когда мы обновляем данные с сервера, потребление памяти увеличивается.

У вас есть идеи, как решить эту проблему? Я действительно не могу понять, как такая ошибка может случиться в SL4!

Некоторые эксперименты предполагали, что вызов ItemsControl.Items.Clear () может помочь. Любой совет, как просто вызвать это каждый раз, когда изменяется ItemSource? Единственное, что мне приходит в голову, это переопределить ItemsSourceProperty и добавить туда обработчик.

EDIT: Оказалось, что утечка происходит в этой ситуации:

  • загрузка сущностей через контекст служб RIA и сохранение их коллекции в свойстве viewmodel
  • привязать представление списка с пользовательским шаблоном данных к свойству с коллекцией объектов
  • обновление объектов через контекст служб RIA

Что происходит, так это то, что хотя сущности обновляются, что видно на виде, потребление памяти растет.

Если привязка отсутствует, обновление сущностей не потребляет больше памяти (возможно, но уровень потребления памяти в конечном итоге возвращается обратно, когда GC выполняет свою работу).

Если вы очистите контекст или просто создадите новый, память также будет в конечном итоге собрана.

Похоже, проблема связана со службами RIA.

Я могу предоставить простой проект, который показывает проблему, если хотите.

ОБНОВЛЕНИЕ: Утечка памяти, кажется, вызвана INotifyDataErrorInfo. Читайте здесь .

Ответы [ 3 ]

2 голосов
/ 23 августа 2010

ОБНОВЛЕНИЕ:

Служебная версия Silverlight 4 для исправления утечек памяти: http://timheuer.com/blog/archive/2010/09/01/silverlight-service-release-september-2010-gdr1.aspx

Silverlight 4 имеет известные проблемы утечки памяти с шаблонами данных.В настоящее время тестирование исправлено.

Вот тема, в которой я следую:

Пользователь "heuertk" - разработчик Microsoft Silverlight .... он объясняетпроблемы и состояние исправления ...

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

1 голос
/ 18 февраля 2011

Эй, я немного поэкспериментировал с вашим решением, я придумал этот обходной путь, который работает довольно хорошо, в основном вы меняете свой класс 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;
    }
}
1 голос
/ 13 сентября 2010

Насколько я понимаю, именно эта проблема является ошибкой в ​​самом Silverlight 4.Тем не менее, вы говорите, что столкнулись с очередной утечкой памяти.Вы определили, было ли это связано с Caliburn.Micro, и если да, разместили ли вы об этом на форумах проектов?Если ошибка в CM, я хотел бы попытаться исправить это.Спасибо.

...