MK>Может у кого еще имеются ссылочки на подобную тему.
Как-то плохо со ссылками.
В первую очередь, очень советую проверять наличие/отсутствие утечек памяти. Где-то тут уже была тема про это.
Последний memory leak, на который я наткнулась — хотела сделать статическую кисть, заморозить ее и использовать везде. Получилось, что если один раз ей что-нибудь нарисуешь, она не освобождает какие-то ссылки, т.е. каждое следующее рисование занимает все больше времени. Обошла тем, что каждый раз возвращаю клон от этой статической кисти.
Во вторую очередь — ничему не верить на слово, проверять с рефлектором.
Если много каких-то объектов, то не делать в каждом из них лишних байндингов или еще каких-то действий на всякий случай, а при необходимости работать с ними из контейнера.
Там, где не можете гарантировать отписку от событий, пользуйтесь WeakEvent паттерном (в MSDN описано).
Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться.
Здравствуйте, notacat.
N>Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться.
ЫЫЫ Не я один на нелюбовь к IDisposable наталкивался...
Я чаще правда ругаюсь что не вызывается IDisposable на биндинге к DataView. Из-за другого бага в самом DataView ломался биндинг у новых DataView к той же таблице. (В DataView есть багофича — change notifying работает только для одного DataView на таблицу. В winForms BindingSource эту проблему как-то обходят. В WPF — нет.)
Дальше тулзы. WPF perf suite с SDK (или как там его???) и mole.
Чаще всего попадались грабли с кривыми template. На втором месте по популярности — попытки "быстро сделать красиво". Как говорится — выбирайте что-то одно
Здравствуйте, notacat, Вы писали:
N>В первую очередь, очень советую проверять наличие/отсутствие утечек памяти. Где-то тут уже была тема про это.
Я создавал тему про утечку при привязке к объектам не DependencyObject и без INotifyPropertyChanged: [WPF] Баг: binding memory leak
.
N>Последний memory leak, на который я наткнулась — хотела сделать статическую кисть, заморозить ее и использовать везде. Получилось, что если один раз ей что-нибудь нарисуешь, она не освобождает какие-то ссылки, т.е. каждое следующее рисование занимает все больше времени. Обошла тем, что каждый раз возвращаю клон от этой статической кисти.
Что-то верится с трудом. Ведь тогда получается, что кистями класса Brushes пользоваться вообще нельзя.
N>Там, где не можете гарантировать отписку от событий, пользуйтесь WeakEvent паттерном (в MSDN описано).
+1
N>Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться.
А в чем чудо? WPF сама вызывает GC.Collect, когда появляется много unmanaged-хэндлов. См. MS.Internal.MemoryPressure в PresentationCore.
N>>Последний memory leak, на который я наткнулась — хотела сделать статическую кисть, заморозить ее и использовать везде. Получилось, что если один раз ей что-нибудь нарисуешь, она не освобождает какие-то ссылки, т.е. каждое следующее рисование занимает все больше времени. Обошла тем, что каждый раз возвращаю клон от этой статической кисти. MK>Что-то верится с трудом. Ведь тогда получается, что кистями класса Brushes пользоваться вообще нельзя.
Не знаю насчет Brushes, возможно это зависит от типа кисти. У меня был градиент, причем сделанный не в xaml, а из кода. Возможно, проблема в этом.
N>>Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться. MK>А в чем чудо? WPF сама вызывает GC.Collect, когда появляется много unmanaged-хэндлов. См. MS.Internal.MemoryPressure в PresentationCore.
Чудо в том, что GC.Collect вызывается, а Dispose — нет. Ну а без Dispose, garbage collector далеко не все умеет чистить.
Здравствуйте, notacat, Вы писали:
N>>>Последний memory leak, на который я наткнулась — хотела сделать статическую кисть, заморозить ее и использовать везде. Получилось, что если один раз ей что-нибудь нарисуешь, она не освобождает какие-то ссылки, т.е. каждое следующее рисование занимает все больше времени. Обошла тем, что каждый раз возвращаю клон от этой статической кисти. MK>>Что-то верится с трудом. Ведь тогда получается, что кистями класса Brushes пользоваться вообще нельзя. N>Не знаю насчет Brushes, возможно это зависит от типа кисти. У меня был градиент, причем сделанный не в xaml, а из кода. Возможно, проблема в этом.
Может быть, может быть... ну если вдруг еще раз встретится, то может запостишь пример
N>>>Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться. MK>>А в чем чудо? WPF сама вызывает GC.Collect, когда появляется много unmanaged-хэндлов. См. MS.Internal.MemoryPressure в PresentationCore. N>Чудо в том, что GC.Collect вызывается, а Dispose — нет. Ну а без Dispose, garbage collector далеко не все умеет чистить.
Если так, то значит какие-то классы внутри WPF криво написано, потому что по правильному Dispose должен вызываться из финализатора.
N>>>>Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться. MK>>>А в чем чудо? WPF сама вызывает GC.Collect, когда появляется много unmanaged-хэндлов. См. MS.Internal.MemoryPressure в PresentationCore. N>>Чудо в том, что GC.Collect вызывается, а Dispose — нет. Ну а без Dispose, garbage collector далеко не все умеет чистить. MK>Если так, то значит какие-то классы внутри WPF криво написано, потому что по правильному Dispose должен вызываться из финализатора.
не криво, а by design, у них в документации прямо написано, что концепция IDisposable в WPF не работает
Здравствуйте, notacat, Вы писали:
N>>>>>Если во фрейме происходит навигация, то IDisposable каким-то чудом срабатывает. Похоже, что единственное такое место в WPF, можно пользоваться. MK>>>>А в чем чудо? WPF сама вызывает GC.Collect, когда появляется много unmanaged-хэндлов. См. MS.Internal.MemoryPressure в PresentationCore. N>>>Чудо в том, что GC.Collect вызывается, а Dispose — нет. Ну а без Dispose, garbage collector далеко не все умеет чистить. MK>>Если так, то значит какие-то классы внутри WPF криво написано, потому что по правильному Dispose должен вызываться из финализатора. N>не криво, а by design, у них в документации прямо написано, что концепция IDisposable в WPF не работает
Странный by design. Т.е. идея то понятна и правильна, на мой взгляд. Другое дело, на фига тогда во внутренних классах этот IDisposable применяется и не вызывается при сборке мусора.
MK>Странный by design. Т.е. идея то понятна и правильна, на мой взгляд. Другое дело, на фига тогда во внутренних классах этот IDisposable применяется и не вызывается при сборке мусора.
А это не факт, что для внутренних классов он не вызывается. Я сейчас в связи с переходом на Сильверлайт этот индусский код изнутри изучаю — полно мест, где они для своих классов делают какую-нибудь специальную обработку, причем в таком месте, о котором нарочно не догадаешься. Очень много internal свойств и методов, которые дергаются отовсюду..
Здравствуйте, notacat, Вы писали:
MK>>Странный by design. Т.е. идея то понятна и правильна, на мой взгляд. Другое дело, на фига тогда во внутренних классах этот IDisposable применяется и не вызывается при сборке мусора. N>А это не факт, что для внутренних классов он не вызывается. Я сейчас в связи с переходом на Сильверлайт этот индусский код изнутри изучаю — полно мест, где они для своих классов делают какую-нибудь специальную обработку, причем в таком месте, о котором нарочно не догадаешься. Очень много internal свойств и методов, которые дергаются отовсюду..
Так. Чего то не понимаю. Мне казалось проблема в том, что где-то внутри WPF не зовется Dispose. Если это не внутри, а в собственном коде, то что мешает поместить вызов Dispose в финализатор?
MK>>>Странный by design. Т.е. идея то понятна и правильна, на мой взгляд. Другое дело, на фига тогда во внутренних классах этот IDisposable применяется и не вызывается при сборке мусора. N>>А это не факт, что для внутренних классов он не вызывается. Я сейчас в связи с переходом на Сильверлайт этот индусский код изнутри изучаю — полно мест, где они для своих классов делают какую-нибудь специальную обработку, причем в таком месте, о котором нарочно не догадаешься. Очень много internal свойств и методов, которые дергаются отовсюду.. MK>Так. Чего то не понимаю. Мне казалось проблема в том, что где-то внутри WPF не зовется Dispose. Если это не внутри, а в собственном коде, то что мешает поместить вызов Dispose в финализатор?
Ничего не мешает, специально сейчас попробовала. В приложении создаются немодальные окна, в которых рисуются мои контролы. Создаю новые окна, закрываю, открываю еще штук 20 окон и т.д... Все это достаточно большое, видно что какая-то сборка мусора происходит, иначе это все разрослось бы до невменяемых размеров. НО финализатор вызывается только при закрытии всего приложения, а там он уже и не нужен, поскольку закрытие приложения все равно память почистит. Мне желательно память освобождать по закрытию окна, чтобы программа у юзера могла сутками работать.
Здравствуйте, notacat, Вы писали:
N>Ничего не мешает, специально сейчас попробовала. В приложении создаются немодальные окна, в которых рисуются мои контролы. Создаю новые окна, закрываю, открываю еще штук 20 окон и т.д... Все это достаточно большое, видно что какая-то сборка мусора происходит, иначе это все разрослось бы до невменяемых размеров. НО финализатор вызывается только при закрытии всего приложения, а там он уже и не нужен,
Сборка второго поколения проходит при этом?
N>>Ничего не мешает, специально сейчас попробовала. В приложении создаются немодальные окна, в которых рисуются мои контролы. Создаю новые окна, закрываю, открываю еще штук 20 окон и т.д... Все это достаточно большое, видно что какая-то сборка мусора происходит, иначе это все разрослось бы до невменяемых размеров. НО финализатор вызывается только при закрытии всего приложения, а там он уже и не нужен, S>Сборка второго поколения проходит при этом?
Не знаю, как это проверить?
Здравствуйте, notacat, Вы писали:
N>Ничего не мешает, специально сейчас попробовала. В приложении создаются немодальные окна, в которых рисуются мои контролы. Создаю новые окна, закрываю, открываю еще штук 20 окон и т.д... Все это достаточно большое, видно что какая-то сборка мусора происходит, иначе это все разрослось бы до невменяемых размеров. НО финализатор вызывается только при закрытии всего приложения, а там он уже и не нужен, поскольку закрытие приложения все равно память почистит. Мне желательно память освобождать по закрытию окна, чтобы программа у юзера могла сутками работать.
Очень странно. Я когда определял, что избавился от описанной ранее утечки в Binding, ставил breakpoint'ы на финализаторы. Закрытые окна со временем собирались, а не только, когда завершалось приложение. Возможно где-то осталась лишняя ссылка.
N>>Ничего не мешает, специально сейчас попробовала. В приложении создаются немодальные окна, в которых рисуются мои контролы. Создаю новые окна, закрываю, открываю еще штук 20 окон и т.д... Все это достаточно большое, видно что какая-то сборка мусора происходит, иначе это все разрослось бы до невменяемых размеров. НО финализатор вызывается только при закрытии всего приложения, а там он уже и не нужен, поскольку закрытие приложения все равно память почистит. Мне желательно память освобождать по закрытию окна, чтобы программа у юзера могла сутками работать. MK>Очень странно. Я когда определял, что избавился от описанной ранее утечки в Binding, ставил breakpoint'ы на финализаторы. Закрытые окна со временем собирались, а не только, когда завершалось приложение. Возможно где-то осталась лишняя ссылка.
Естественно, лишняя ссылка, как бы только эту ссылку убирать при удалении контрола, если учесть, что контрол может хоститься в окне, на странице, еще где-нибудь, может удаляться из окна, когда окно никто не закрывает, и т.д. (юзеры придумывали мне кучу вариантов). По Unloaded этого делать нельзя, поскольку один и тот же контрол может быть после Unloaded снова Loaded. А если лишних ссылок нет — то и Dispose наверное не нужен.
А сгружать эту задачу на юзера моих контролов — нехорошо. Самое главное, что в WinForms с этим проблем вообще не было, там Dispose отрабатывал когда нужно.
S>>>Сборка второго поколения проходит при этом? N>>Не знаю, как это проверить? S>Профайлером
научи меня, ты каким профайлером пользуешься? У меня только то, что в Team System входит.
Здравствуйте, notacat, Вы писали:
N>>>Ничего не мешает, специально сейчас попробовала. В приложении создаются немодальные окна, в которых рисуются мои контролы. Создаю новые окна, закрываю, открываю еще штук 20 окон и т.д... Все это достаточно большое, видно что какая-то сборка мусора происходит, иначе это все разрослось бы до невменяемых размеров. НО финализатор вызывается только при закрытии всего приложения, а там он уже и не нужен, поскольку закрытие приложения все равно память почистит. Мне желательно память освобождать по закрытию окна, чтобы программа у юзера могла сутками работать. MK>>Очень странно. Я когда определял, что избавился от описанной ранее утечки в Binding, ставил breakpoint'ы на финализаторы. Закрытые окна со временем собирались, а не только, когда завершалось приложение. Возможно где-то осталась лишняя ссылка. N>Естественно, лишняя ссылка, как бы только эту ссылку убирать при удалении контрола, если учесть, что контрол может хоститься в окне, на странице, еще где-нибудь, может удаляться из окна, когда окно никто не закрывает, и т.д. (юзеры придумывали мне кучу вариантов). По Unloaded этого делать нельзя, поскольку один и тот же контрол может быть после Unloaded снова Loaded. А если лишних ссылок нет — то и Dispose наверное не нужен.
Я говорил о лишних ссылках на контрол, о ссылках, которые не позволяют GC вызвать финализатор до закрытия приложения. Если же речь идет о детерминированном высвобождении ресурсов, то да, WPF это не поддерживает.
S>>>>Сборка второго поколения проходит при этом? N>>>Не знаю, как это проверить? S>>Профайлером N>научи меня, ты каким профайлером пользуешься? У меня только то, что в Team System входит.
Починила счетчики производительности в системе, посмотрела — собирается второе поколение тоже.