Знакомая картина: вы пишете десктопное или IoT-приложение, настраиваете архитектуру, код блестит. Приложение управляет оборудованием в режиме 24/7. Стенд без проблем отрабатывает пару смен, а через неделю память незаметно раздувается в гигабайты, и система падает.
В 90% случаев дело не в тяжелых массивах или картинках. Причина кроется в коварной связке механики событий и жизненного цикла DI-контейнера.
Как выглядит классический "тихий убийца" памяти: 1. Долгоживущий сервис (Singleton или глобальный Store) объявляет событие. 2. Короткоживущий UI-компонент (ViewModel конкретного View элемента) подписывается на него через обычный "+=". 3. Пользователь закрывает экран. ViewModel больше не нужна, но сборщик мусора (GC) не может её удалить. В графе объектов она остаётся "живой", потому что на неё всё еще ссылается делегат события из Singleton-сервиса.
Казалось бы, решение банальное - реализуй IDisposable и аккуратно отписывайся через "-=". Но давайте смотреть правде в глаза. На масштабе проекта в 2000+ файлов человеческий фактор сработает на 100%. Кто-то точно забудет отписаться.
Что реально помогает держать объем занятой памяти в норме при бесконечном потоке данных?
1. Используйте слабые события для интерфейса. Если экран закрыли, система не будет насильно удерживать его в памяти из-за подписки. 2. Экраны не должны напрямую "слушать" шину данных. Они получают потоки, которые автоматически и гарантированно закрываются при закрытии самого экрана. 3. Никакой веры в "clean code". Только регулярные тесты потребления памяти на длинных дистанциях через профилировщики памяти (например, dotMemory).
Последние несколько лет я плотно занимаюсь отказоустойчивой архитектурой систем реального времени: от написания драйверов портов (COM, USB/HID) до создания кроссплатформенного интерфейса под Windows и Linux.
Сейчас я открыт к профессиональному общению и буду рад обсудить сложные архитектурные вызовы в направлениях .NET, индустриального интернета вещей (Industrial IoT) и распределенных систем.
Коллеги, вопрос к вам: с какими самыми коварными утечками памяти в реальных проектах сталкивались вы? Что в итоге оказалось виновником?