Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923

MVVM Утечка памяти

12.06.2022, 20:22. Показов 4545. Ответов 82
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Собственно сделал подписку: _messageService.MessagesChanged += OnMessagesChanged; в VM.
А отписывать-то как?

Сделал так:

https://github.com/LimeniyeCyb... del.cs#L82

Но даже не понимаю.что сделал. Этого будет достаточно?
0
Лучшие ответы (1)
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
12.06.2022, 20:22
Ответы с готовыми решениями:

Утечка памяти с картинками
у меня есть вот такой контрол <StackPanel x:Name="StackEmoji" Grid.Row="1" Grid.Column="1" ...

Dispatch timer - Утечка памяти
Всем привет. Пишу на подобные форумы первый раз. Хотел бы попросить помочь разобраться в ситуации с "утечкой памяти". Есть...

Утечка памяти в Awesomium WebControl
Всем привет. Использую в качестве встроенного браузера Awesomium, но вот проблема, уже страниц через 20 процесс awesomium_process.exe...

82
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
20.06.2022, 22:10  [ТС]
Студворк — интернет-сервис помощи студентам
Элд Хасп, сделал так для чата:
C#
1
BindingOperations.EnableCollectionSynchronization(Messages, ((ICollection)Messages).SyncRoot);
https://github.com/LimeniyeCyb... ebc0717d92

Но так как сообщения у меня не летат -- разницы никакой нет.

То ли дело стриминг с камеры.
Мне с сервера приходят байты новой картинки. Делал так:
C#
1
2
3
4
5
6
7
8
9
10
        public ObservableDictionary<Guid, CaptureFrameViewModel> CaptureFrameAreas { get; } = new ObservableDictionary<Guid, CaptureFrameViewModel>();
 
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            dispatcher.BeginInvoke(() =>
            {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
            });
        }
Работало нормально. Поменял:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
       public CaptureFramesViewModel(...)
        {
            BindingOperations.EnableCollectionSynchronization(CaptureFrameAreas, ((ICollection)CaptureFrameAreas).SyncRoot);
            // ... 
        }
 
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            lock (((ICollection)CaptureFrameAreas).SyncRoot)
            {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
            };
        }
Начались промежуточные просадки кадров.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
20.06.2022, 22:45
Цитата Сообщение от limeniye Посмотреть сообщение
Мне с сервера приходят байты новой картинки. Делал так:
Вы не меняете коллекцию, вы читаете из неё.
Здесь обо ваших варианта неверны.

Просто читайте без локировки и перехода в UI поток:

C#
1
2
3
4
5
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
        }
Локировка нужна только для потокобезопасности.
У вас, как я понял, такой задачи не стоит - следовательно вам она не нужна.
Просто передали объект синхронизации в привязку, чтобы не выкидывало исключений, и дальше "забыли про него".
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
20.06.2022, 22:59  [ТС]
Элд Хасп, выглядит логично:
C#
1
2
3
4
5
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
        }
Но на деле -- смешно, но всё равно тормозит.
Единственная вариация, в которой не тормозит:
C#
1
2
3
4
5
6
7
8
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            dispatcher.BeginInvoke(() =>
            {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
            });
        }
https://github.com/LimeniyeCyb... #L165-L172


Добавлено через 43 секунды
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Просто передали объект синхронизации в привязку, чтобы не выкидывало исключений, и дальше "забыли про него".
тут уловил связь: о чём речь?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
20.06.2022, 23:05
Цитата Сообщение от limeniye Посмотреть сообщение
сделал так для чата:
Чтобы не писать каждый раз однотипный код - объявите методы расширения:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using System.Collections;
using System.Threading;
using System.Windows;
using System.Windows.Data;
using System.Windows.Threading;
 
namespace CommonCore
{
    public static class CollectionHelper
    {
        public static void EnableCollectionSynchronization(this ICollection collection)
        {
            if (collection is null)
                return;
            if (SynchronizationContext.Current is DispatcherSynchronizationContext context)
            {
                BindingOperations.EnableCollectionSynchronization(collection, collection.SyncRoot);
            }
            else
            {
                Application.Current.Dispatcher.Invoke(collection.EnableCollectionSynchronization);
            }
        }
        public static void DisableCollectionSynchronization(this ICollection collection)
        {
            if (collection is null)
                return;
            if (SynchronizationContext.Current is DispatcherSynchronizationContext context)
            {
                BindingOperations.DisableCollectionSynchronization(collection);
            }
            else
            {
                Application.Current.Dispatcher.Invoke(collection.DisableCollectionSynchronization);
            }
        }
    }
}
И потом вызываете их:
C#
1
Messages.EnableCollectionSynchronization();
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
20.06.2022, 23:07  [ТС]
тут уловил связь: о чём речь?
не*
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
20.06.2022, 23:17
Цитата Сообщение от limeniye Посмотреть сообщение
тут уловил связь: о чём речь?
Не надо потом локировать коллекцию, если не нужно потокобезопасность.
Вызвали в конструкторе Messages.EnableCollectionSynchronization() и всё - этого хватает чтобы исключений не выкидывало.

Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Но на деле -- смешно, но всё равно тормозит.
Единственная вариация, в которой не тормозит:
Значит проблема в этой строке: area.Data = e.Bytes;.
Метод OnCaptureFrameChanged в каком потоке вызывается?
Если в UI потоке, то при большом размере e.Bytes может лагать.

Добавлено через 4 минуты
Судя по названию, метод OnCaptureFrameChanged похож на обработчик события какого-то UI элемента.
Если я прав, то тогда он должен быть таким:
C#
1
2
3
4
5
6
7
8
        private async void OnCaptureFrameChangedAsync(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            await Task.Run(() =>
            {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
            });
        }
Добавлено через 1 минуту
Но это для WPF!
На UWP area.Data = e.Bytes должно происходить в UI потоке.
И для UWP вариант с Диспетчером верный.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
20.06.2022, 23:29  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Судя по названию, метод OnCaptureFrameChanged похож на обработчик события какого-то UI элемента.

Нет, из модели, и вызывается в другом потоке.

Добавлено через 4 минуты
это WPF проект.

С этой записью подтормаживает также, как и со всеми другими где не dispatcher.BeginInvoke(() => {} ); :
C#
1
2
3
4
5
6
7
8
        private async void OnCaptureFrameChangedAsync(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            await Task.Run(() =>
            {
                var area = CaptureFrameAreas[e.CaptureAreadGuid];
                area.Data = e.Bytes;
            });
        }
Это с учтётом того, что я CaptureFrameAreas.EnableCollectionSynchronization();
https://github.com/LimeniyeCyb... del.cs#L35
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
20.06.2022, 23:45
Цитата Сообщение от limeniye Посмотреть сообщение
Нет, из модели, и вызывается в другом потоке.
Странно.....
Но, это как связанно с изменением свойства.

Вот так попробуйте, чтобы убедиться.
C#
1
2
3
4
5
6
7
8
9
        private async void OnCaptureFrameChangedAsync(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
           var area = CaptureFrameAreas[e.CaptureAreadGuid];
 
            await Task.Run(() =>
            {
                area.Data = e.Bytes;
            });
        }
P.S. Плохая привычка - использовать var если сразу в строке нет указания его типа.
То есть вот можно var point = new Point (...), а вот как у вас делает код плохочитаемым.

Добавлено через 1 минуту
А в актуальной версии, даже вариант с конструктором не желательно использовать.
Нужно так: Point point = new(...);.

Добавлено через 4 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Это с учтётом того, что я CaptureFrameAreas.EnableCollectionSynchr onization();
https://github.com/LimeniyeCyb... del.cs#L35
Блин у вас же CaptureFrameAreas - это словарь.
С ним, вообще, по другому работать надо.
И ещё зависит от реализации словаря.
Во всех реализациях ObservableDictionary при любом изменении словаря вызывается ПОЛНЫЙ рендеринг всего словаря.
Способа вызвать рендеринг только одного ключа или значения НЕ СУЩЕСТВУЕТ.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
20.06.2022, 23:51  [ТС]
Элд Хасп, подтормаживает:
C#
1
2
3
4
5
6
var area = CaptureFrameAreas[e.CaptureAreadGuid];
 
await Task.Run(() =>
{
    area.Data = e.Bytes;
});
Я расписал: как запустить приложение локально в Readme:
https://github.com/LimeniyeCyberforum/Meeting

Там ничего сложного: просто изменить false на true и запускать сервер вместе c WPF приложением нужно.
Гляньте, может станет ясней, а то пальцем в небо тыкаем.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
21.06.2022, 00:05
Цитата Сообщение от limeniye Посмотреть сообщение
Гляньте, может станет ясней, а то пальцем в небо тыкаем.
Уже написал выше в чём дело.
В WPF/UWP нет дефолтной реализации обновления словаря.
Все эти ObservableDictionary - это попытки замаскировать словарь под наблюдаемый список.
И ни одна из них никогда не будет в полной мере работать как ObservableCollection.
У всех у них есть ограничения и какие-то нюансы для правильной работы.

Я, вообще, не советую их использовать в привязках, особенно, если они большие и/или быстро меняющиеся.


Цитата Сообщение от limeniye Посмотреть сообщение
подтормаживает:
Тогда точно дело в самом рендеринге свойства area.Data.

Попробуйте заменить на диспетчер и лагов не будет, но по сути это костыль и скорее говорит об архитектурных проблемах, чем о том что вот так правильно решать.
Если всё реализовано верно, то VM не должна ничего знать о Диспетчере.
C#
1
2
3
4
5
6
var area = CaptureFrameAreas[e.CaptureAreadGuid];
 
dispatcher.BeginInvoke(() =>
{
    area.Data = e.Bytes;
});
Добавлено через 59 секунд
Цитата Сообщение от limeniye Посмотреть сообщение
Гляньте,
Возможно, завтра.
Напомните после обеда.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
21.06.2022, 00:08  [ТС]
Элд Хасп, его Set<T> обычный
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
21.06.2022, 14:09
Цитата Сообщение от limeniye Посмотреть сообщение
Гляньте, может станет ясней, а то пальцем в небо тыкаем.
1) CaptureFramesUserControl показ кадров::
XML
27
28
    <Image x:Name="captureFrame" Source="{Binding Value.Data}"
           Stretch="Uniform" Visibility="Visible"/>
Value.Data - это массив байт. И при его изменении привязка будет синхронно в UI потоке его конвертировать в ImageSource.

Можно попробовать Source="{Binding Value.Data, IsAsync=True}".
Если не поможет, то нужно делать "ручную" конвертацию в таске.

2) CaptureFramesUserControl привязка к словарю:
XML
17
        <ItemsControl ItemsSource="{Binding CaptureFramesVM.CaptureFrameAreas}">
Зачем здесь словарь? "Чтобы был!"?
Здесь нужна ObservableCollection.

3) По всему проекту много предупреждений Студии о nullable контексте.
Почему не устраняете их?

Добавлено через 4 минуты
4) Реализация метода OnCaptureFrameChanged должна быть такой:
C#
159
160
161
162
163
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            CaptureFrameViewModel? area = CaptureFrameAreas[e.CaptureAreadGuid];
            area.Data = e.Bytes;
        }
Не надо сюда запихивать Диспетчер.
Нужно разбираться с причиной лагов, а не добавлять костыли.

Добавлено через 2 минуты
Не совсем такой - так как CaptureFrameAreas надо заменить на ObservableCollection или использовать и её и словарь.
Но привязка должна быть именно к ObservableCollection.
А словарь можно использовать для быстрого обновления данных камер.
Хотя если камер в пределах сотни, то словарь здесь и вовсе не нужен.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
21.06.2022, 16:53  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Можно попробовать Source="{Binding Value.Data, IsAsync=True}".
Не помогло

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Зачем здесь словарь? "Чтобы был!"?
Мне кажется тут концептуально подходит именно словарь.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
3) По всему проекту много предупреждений Студии о nullable контексте.
Почему не устраняете их?
Сейчас гляну
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
21.06.2022, 18:49
Цитата Сообщение от limeniye Посмотреть сообщение
Мне кажется тут концептуально подходит именно словарь.
Публичный словарь там точно не нужен.
Должно быть нечто подобное:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
        // Публичное свойство для привязки.
        public ObservableCollection<SomeType> Items { get; } = new ObservableCollection<SomeType>();
        // Внутренний словарь для быстрого поиска.
        private readonly Dictionary<int, SomeType> itemsDictionary = new Dictionary<int, SomeType>();
 
        // Метод обновления. Получает действие обновления и данные для обновления.
        private void OnUpdate(UpdateAction action, SomeData data)
        {
            switch (action)
            {
                // Если "Добавить", то создаётся новая сущность
                // и она добавляется в ObservableCollection и в словарь.
                case UpdateAction.Add:
                    {
                        SomeType item = new SomeType(data);
                        Items.Add(item);
                        itemsDictionary.Add(item.Id, item);
                    }
                    break;
 
                // Если "Удалить", то сущность извлекается из словаря и
                // потом удаляется в  ObservableCollection и в словаре.
                // и она добавляется в ObservableCollection и в словарь.
                case UpdateAction.Remove:
                    {
                        if (itemsDictionary.TryGetValue(data.Id, out SomeType item))
                        {
                            Items.Remove(item);
                            itemsDictionary.Remove(item.Id);
                        }
                    }
                    break;
 
                // Если "Обновить", то сущность извлекается из словаря и
                // потом обновляется актуальными данными.
                case UpdateAction.Update:
                    {
                        if (itemsDictionary.TryGetValue(data.Id, out SomeType item))
                        {
                            item.Update(data);
                        }
                    }
                    break;
 
                default:
                    throw new ArgumentException($"Неожиданное значение^ {(int)action}", nameof(action));
            }
        }
Добавлено через 4 минуты
Но конкретно в данной задаче, даже такой словарь это излишние сложности.
Время обычного линейного поиска по списку из сотен элементов - максимум единицы микросекунды, а возможно даже и доли микросекунды.
Время обновления WPF представления единицы и десятки миллисекунды.
Разница на 3-5 порядков.

Добавлено через 3 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Не помогло
Тогда явная асинхронная конвертация.
Свойство Data делаете ImageSource, полученный массив байт конвертируете в BitmapImage, замораживаете и записывает в свойство Data.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
21.06.2022, 19:38  [ТС]
Элд Хасп, для чего я сделал Dictonary

Типы разные -- Guid -- одинаковый.
Что банально добавить или изменить элемент, мне нужно сделать столько действий:
C#
1
2
3
4
5
6
7
8
9
10
11
                    CaptureFrameViewModel? captureFrameArea = CaptureFrameAreas.FirstOrDefault(x => x.AreaGuid == e.CaptureAreadGuid);
                    int index = captureFrameArea is null ? -1 : CaptureFrameAreas.IndexOf(captureFrameArea);
                    if (index > -1)
                    {
                        CaptureFrameAreas[index].Data = null;
                    }
                    else
                    {
                        user = _meetingUsers.Users.Users[e.OwnerGuid];
                        CaptureFrameAreas.Add(new CaptureFrameViewModel(e.OwnerGuid, e.CaptureAreadGuid, user.UserName, null));
                    }
Выходит весьма громоздко: сначала нужно найти элемент с таким Id, потому что приходит Dto, а храню я Vm.
Потом нужно узнать его индекс. И если индекс больше -1 -- тогда ряд операций.
как-то много

Добавлено через 8 минут
Элд Хасп, переделал на ObservableCollection -- не помогло.
По прежнему без обёртки в Dispatcher -- подтормаживает. Значит дело не в нём

Добавлено через 10 минут
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Свойство Data делаете ImageSource, полученный массив байт конвертируете в BitmapImage, замораживаете и записывает в свойство Data.
Я оставил байты, сделал Converter -- не помогло (это с ObservableCollection).
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
21.06.2022, 20:07
Цитата Сообщение от limeniye Посмотреть сообщение
переделал на ObservableCollection -- не помогло.
Это и недолжно было помочь.
Это вообще о другом - что неверно используете типы, неверный подход к реализации.

Цитата Сообщение от limeniye Посмотреть сообщение
Я оставил байты, сделал Converter -- не помогло (это с ObservableCollection).
Converter не поможет, так как он будет вызываться в UI потоке, а не в потоке присвоения Data.
Сделайте конвертацию сразу присвоения, чтобы понять помогает это или нет.
Если поможет, то уже покажу как убрать ItemsSource из VM.
И убедитесь что метод OnCaptureFrameChanged вызывается в задаче, а не в UI потоке или в другом одном и том же потоке.

Добавлено через 2 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
Выходит весьма громоздко: сначала нужно найти элемент с таким Id ....
Да, не громоздко это.
Это нормально.
При любом раскладе словарю не место в свойствах VM (для данной задачи).

Добавлено через 2 минуты
Словарь имел бы какое-то смысл если бы у вас были к нему привязки по ключам (а не по индексам).
У вас такого нет.
Ни какие другие аргументы не могут быть основанием для введения словаря.

Если вам удобно реализовывать логику VM через него - ради бога.
Но Представление зачем знать об этой логике?
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
21.06.2022, 21:20  [ТС]
Элд Хасп, я попытался изменить Byte[] на BitmapImage? Data.
Цитата Сообщение от Элд Хасп Посмотреть сообщение
И убедитесь что метод OnCaptureFrameChanged вызывается в задаче
Да, но чтобы Вы были уверены ещё и внутри добавил:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        private async void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            await Task.Run(() =>
            {
                CaptureFrameViewModel? captureFrameArea = CaptureFrameAreas.FirstOrDefault(x => x.AreaGuid == e.CaptureAreadGuid);
                int index = captureFrameArea is null ? -1 : CaptureFrameAreas.IndexOf(captureFrameArea);
                if (index > -1)
                {
                    if (e.Bytes is not null)
                        CaptureFrameAreas[index].Data = e.Bytes.ConvertByteArrayToBitmapImage();
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine($"FrameArea not exitst {e}");
                }
            });
        }
Из xaml ковертер убрал
XML
1
2
                        <Image x:Name="captureFrame" Source="{Binding Data, IsAsync=True}"
                               Stretch="Uniform" Visibility="Visible"/>
После изменения значения на этой строке CaptureFrameAreas[index].Data = e.Bytes.ConvertByteArrayToBitmapImage(); вылетает диалоговое окно и исключение.
При чём если обернуть эту строку в try/catch -- окно всё равно будет вылетать, значит ошибка где-то в другом месте появляется.


Exception
Кликните здесь для просмотра всего текста

This exception was originally thrown at this call stack:
System.Windows.DependencyObject.Validate Sources(System.Windows.DependencyObject, System.Windows.DependencySource[], System.Windows.Expression)
System.Windows.Expression.ChangeSources( System.Windows.DependencyObject, System.Windows.DependencyProperty, System.Windows.DependencySource[])
System.Windows.Data.BindingExpressionBas e.ChangeSources(System.Windows.Dependenc yObject, System.Windows.DependencyProperty, MS.Internal.Data.WeakDependencySource[])
System.Windows.Data.BindingExpressionBas e.ChangeSources(MS.Internal.Data.WeakDep endencySource[])
System.Windows.Data.BindingExpression.Ch angeWorkerSources(MS.Internal.Data.WeakD ependencySource[], int)
MS.Internal.Data.ClrBindingWorker.Replac eDependencySources()
MS.Internal.Data.ClrBindingWorker.NewVal ueAvailable(bool, bool, bool)
MS.Internal.Data.PropertyPathWorker.Upda teSourceValueState(int, System.ComponentModel.ICollectionView, object, bool)
MS.Internal.Data.PropertyPathWorker.Refr eshValue()
MS.Internal.Data.ClrBindingWorker.Schedu leTransferOperation(object)


StackTrace
Кликните здесь для просмотра всего текста

at System.Windows.DependencyObject.Validate Sources(DependencyObject d, DependencySource[] newSources, Expression expr)
at System.Windows.Expression.ChangeSources( DependencyObject d, DependencyProperty dp, DependencySource[] newSources)
at System.Windows.Data.BindingExpressionBas e.ChangeSources(DependencyObject target, DependencyProperty dp, WeakDependencySource[] newSources)
at System.Windows.Data.BindingExpressionBas e.ChangeSources(WeakDependencySource[] newSources)
at System.Windows.Data.BindingExpression.Ch angeWorkerSources(WeakDependencySource[] newWorkerSources, Int32 n)
at MS.Internal.Data.ClrBindingWorker.Replac eDependencySources()
at MS.Internal.Data.ClrBindingWorker.NewVal ueAvailable(Boolean dependencySourcesChanged, Boolean initialValue, Boolean isASubPropertyChange)
at MS.Internal.Data.PropertyPathWorker.Upda teSourceValueState(Int32 k, ICollectionView collectionView, Object newValue, Boolean isASubPropertyChange)
at MS.Internal.Data.PropertyPathWorker.Refr eshValue()
at MS.Internal.Data.ClrBindingWorker.Schedu leTransferOperation(Object arg)
at MS.Internal.Data.DataBindEngine.ProcessC rossThreadRequests()
at System.Windows.Threading.ExceptionWrappe r.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrappe r.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.DispatcherOpera tion.InvokeImpl()
at MS.Internal.CulturePreservingExecutionCo ntext.CallbackWrapper(Object obj)
at System.Threading.ExecutionContext.RunInt ernal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.Excepti onDispatchInfo.Throw()
at MS.Internal.CulturePreservingExecutionCo ntext.Run(CulturePreservingExecutionCont ext executionContext, ContextCallback callback, Object state)
at System.Windows.Threading.DispatcherOpera tion.Invoke()
at System.Windows.Threading.Dispatcher.Proc essQueue()
at System.Windows.Threading.Dispatcher.WndP rocHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallback Operation(Object o)
at System.Windows.Threading.ExceptionWrappe r.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
at System.Windows.Threading.ExceptionWrappe r.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.Lega cyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
at MS.Win32.HwndSubclass.SubclassWndProc(In tPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMes sage(MSG& msg)
at System.Windows.Threading.Dispatcher.Push FrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Push Frame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run( )
at System.Windows.Application.RunDispatcher (Object ignore)
at System.Windows.Application.RunInternal(W indow window)
at System.Windows.Application.Run()
at Meeting.Wpf.App.Main()


Добавлено через 6 минут
Изменил, ради теста, запись на следущую:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
        private void OnCaptureFrameChanged(object? sender, Business.Common.EventArgs.CaptureFrameEventArgs e)
        {
            dispatcher.BeginInvoke(() =>
            {
                CaptureFrameViewModel? captureFrameArea = CaptureFrameAreas.FirstOrDefault(x => x.AreaGuid == e.CaptureAreadGuid);
                int index = captureFrameArea is null ? -1 : CaptureFrameAreas.IndexOf(captureFrameArea);
                if (index > -1)
                {
                    if (e.Bytes is not null)
                        CaptureFrameAreas[index].Data = e.Bytes.ConvertByteArrayToBitmapImage();
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine($"FrameArea not exitst {e}");
                }
            });
        }
Ошибка пропала, ничего не глючит, но видно, что некоторые кадры пропадают.
Не тормозит, а именно самого кадра нет. Как-будто null отобразило. Странно.

Добавлено через 3 минуты
Удалил IsAsync=True и теперь всё нормально

Добавлено через 11 минут
В общем, потестил и вдоль и поперёк -- безрезультатно.
Куда-то не в ту сторону копаю.

Добавлено через 13 минут
Вроде решил проблему.
С самого начала мне казалось что дело в свойстве, а именно в его Set.

Цитата Сообщение от limeniye Посмотреть сообщение
Элд Хасп, его Set<T> обычный
В общем, как я решил проблему, я запихнул в Set -- диспатчеризацию:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    public abstract partial class BaseInpc : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
 
        protected void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
        {
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
            DispatchAsync(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)));
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
        }
 
        protected bool Set<T>(ref T propertyField, T newValue, Equality<T>? equality = null, [CallerMemberName] string? propertyName = null)
        {
            bool isEquals = propertyField == null || newValue == null
                ? propertyField == null && newValue == null
                : ReferenceEquals(propertyField, newValue) ||
                    (
                        equality != null
                        ? equality(propertyField, newValue)
                        : propertyField is IEquatable<T> equatable
                            ? equatable.Equals(newValue)
                            : propertyField.Equals(newValue)
                    );
            if (!isEquals)
            {
                T oldValue = propertyField;
                propertyField = newValue;
                RaisePropertyChanged(propertyName);
 
                ProtectedPropertyChanged?.Invoke(propertyName, oldValue, newValue);
            }
 
            return !isEquals;
        }
 
        protected async Task DispatchAsync(Action callback)
        {
            if (SynchronizationContext.Current is DispatcherSynchronizationContext context)
            {
                callback.Invoke();
            }
            else
            {
                await Application.Current.Dispatcher.InvokeAsync(callback, DispatcherPriority.Normal);
            }
        }
 
        protected static event PropertyChangedHandler? ProtectedPropertyChanged;
    }
И это, слава Аллаху -- помогло.

Добавлено через 11 минут
https://github.com/LimeniyeCyb... e752c7f7ab
https://github.com/LimeniyeCyb... 52b3c80d36
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
21.06.2022, 21:21
Цитата Сообщение от limeniye Посмотреть сообщение
Ошибка пропала, ничего не глючит, но видно, что некоторые кадры пропадают.
Код метода ConvertByteArrayToBitmapImage() покажите.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
21.06.2022, 21:23  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Код метода ConvertByteArrayToBitmapImage() покажите.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
        public static BitmapImage? ConvertByteArrayToBitmapImage(this byte[] bytes)
        {
            if (bytes.Length <= 0)
                return null;
 
            var stream = new MemoryStream(bytes);
            stream.Seek(0, SeekOrigin.Begin);
            var image = new BitmapImage();
            image.BeginInit();
            image.StreamSource = stream;
            image.EndInit();
            return image;
        }
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,175
Записей в блоге: 2
21.06.2022, 21:28
Цитата Сообщение от limeniye Посмотреть сообщение
В общем, как я решил проблему, я запихнул в Set -- диспатчеризацию:
Ну, вы всё запихнули в UI поток.
Это говорит о том, что проблемы с синхронизацией потоков, но перекидывать всё в UI поток - не вариант.

К сожалению, как мы выяснили, проверить у себя я не могу - ваша программа не запускается без камеры.

Добавлено через 3 минуты
Цитата Сообщение от limeniye Посмотреть сообщение
return image;
А где заморозка?
Я же писал об этом:
Цитата Сообщение от Элд Хасп Посмотреть сообщение
конвертируете в BitmapImage, замораживаете
C#
11
12
13
14
15
16
            image.EndInit();
 
            image.Freeze(); // ОБЯЗАТЕЛЬНО!
 
            return image;
        }
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
21.06.2022, 21:28

Возможна ли утечка памяти в следующем коде
Имеем следующу последовательность высокочастотных операций, требуется оптимизация т к память съедает в течении дня до 1 Гб: ...

Утечка памяти при обновлении текста TextBlock
При каждом тике таймера обновляется текст TextBlock'a. private void Paint(object sender, EventArgs e) { ...

Утечка памяти при большом количестве сообщений
Есть окно сообщения.При новом сообщения создается новое окно(анимировано),старое закрывается(Close).В этом окне есть одно Image.Если много...

Программа не может продолжить работу, так как недостаточно памяти. Утечка в WPF?
В общем, есть у меня контрол, который наследует от Image, воспроизводит анимацию просто сменяя изображения из массива. А сменяются...

HttpWebRequest, расход памяти непомерно больших объемов и , как следствие, утечка памяти
Добрый вечер. Мне была поставлена такая задача. Написать приложение, которая загружает из списка ссылки с сайта и ищет там определенную...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru