Форум программистов, компьютерный форум, киберфорум
C# Windows Forms
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
Рейтинг 4.71/7: Рейтинг темы: голосов - 7, средняя оценка - 4.71
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467

Как справиться с утечкой памяти в коде?

27.03.2017, 14:03. Показов 1802. Ответов 19
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть вот такая форма
Кликните здесь для просмотра всего текста

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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
   internal partial class FindDialogForm<T> : XtraForm {
        public List<T> SelectedItems { get; private set; } = new List<T>();
        private List<TableItem> _dataSource = new List<TableItem>();
        class TableItem {
            public T Base { get; set; }
            public string Type { get; set; }
        }
 
        public FindDialogForm(bool allowMultiple, bool group) {
            InitializeComponent();
 
            DialogResult = DialogResult.Cancel;
 
            _gridControl.DataSource = _dataSource;
            _gridView.OptionsSelection.MultiSelect = allowMultiple;
            if (!group) {
                _groupColumn.GroupIndex = -1;
                _groupColumn.Visible = false;
            }
 
            foreach (var pi in typeof(T).GetProperties()) {
                var col = _gridView.Columns.AddVisible($"Base.{pi.Name}");
                if (pi.PropertyType == typeof(int)) {
                    col.MaxWidth = 60;
                    col.MinWidth = 60;
                }
 
                if (pi.PropertyType == typeof(Bitmap)) {
                    col.ColumnEdit = new DevExpress.XtraEditors.Repository.RepositoryItemPictureEdit();
                    col.MaxWidth = 25;
                    col.MinWidth = 25;
                }
            }
        }
 
        public void AddDataSource(IEnumerable<T> data, string name = null) {
            _dataSource.AddRange(data.Select(d => new TableItem() { Base = d, Type = name }));
            _gridControl.RefreshDataSource();
        }
 
        private void _okBtn_Click(object sender, EventArgs e) {
            foreach (var i in _gridView.GetSelectedRows()) {
                if (i == -1) {
                    continue;
                }
 
                var item = _gridView.GetRow(i) as TableItem;
                SelectedItems.Add(item.Base);
            }
 
            DialogResult = SelectedItems.Any() ? DialogResult.OK : DialogResult.Cancel;
 
            Close();
        }
 
        private void _dlgGridView_DoubleClick(object sender, EventArgs e) {
            var rows = _gridView.GetSelectedRows();
            if (!rows.Any() || rows.Contains(-1)) {
                return;
            }
 
            _okBtn_Click(null, null);
        }
    }


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

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
        class DataTableItem {
            private BaseData _inner;
            private Bitmap _icon;
            private static Bitmap _empty = new Bitmap(20, 20);
            public Bitmap Icon {
                get {
                    if (_icon == null) {
                        _icon = _inner.Icon == null ? _empty : new Bitmap(new MemoryStream(_inner.Icon));
                    }
 
                    return _icon;
                }
            }
            public int Id { get { return _inner.Id; } }
            public string Name { get { return _inner.Name; } }
 
            public static DataTableItem Create(BaseData inner) {
                return new DataTableItem() { _inner = inner };
            }
        }
 
        private void button5_Click(object sender, EventArgs e) {
            using (var dlg = new FindDialogForm<DataTableItem>(true, true)) {
                dlg.AddDataSource(Engine.Instance.GameData.Actions.Values.Select(DataTableItem.Create), ""); 
                //..
                //объектов в сумме создается ~10к
                dlg.ShowDialog(this);
            }
            
        }


Внешних ссылок, как видно, я не держу.
При открытии, потребляемая память увеличивается на ~10мб(ожидаемо). При закрытии, её объем не уменьшается ни на байт. При повторных открытиях - память увеличивает/уменьшается на ~1мб, при этом её уровень остается "начальный +10". А хотелось бы, что бы после закрытия память возвращалась в исходное состояние.

з.ы. вариант с _dataSource.Clear(); _dataSource = null; GC.Collect(); работает, но есть мнение, что так делать нельзя.

А главное мне не понятно, как я должен управлять памятью в языке со сборщиком мусора?
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
27.03.2017, 14:03
Ответы с готовыми решениями:

Не могу справиться с утечкой памяти TChromium
Добрый день Нужна помощь, пишу примитивный браузер на d2010 с использованием TChromium у меня жутко течет память... Пробовал на...

Как бороться с утечкой памяти?
Добрый день! у меня такая проблема: в моей программе видимо где-то проблемы с утечкой памяти. если много раз запустить - закрыть прогу,...

Setjmp, longjmp, malloc - как бороться с утечкой памяти
Здравствуйте! Вот небольшой тестовый пример, в котором, как я понимаю, free(buf) никогда не выполнится. exit(...) борится только с...

19
1168 / 886 / 517
Регистрация: 09.04.2014
Сообщений: 2,102
27.03.2017, 14:36
Цитата Сообщение от jr_ Посмотреть сообщение
как я должен управлять памятью в языке со сборщиком мусора?
никак - разрешить управлять ею среде .Net
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
27.03.2017, 17:51  [ТС]
Цитата Сообщение от nedel Посмотреть сообщение
никак - разрешить управлять ею среде .Net
я бы рад
0
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
27.03.2017, 18:03
Цитата Сообщение от jr_ Посмотреть сообщение
з.ы. вариант с _dataSource.Clear(); _dataSource = null; GC.Collect(); работает, но есть мнение, что так делать нельзя.
Это значит, что утечек нет. Сборщик мусора сам решает, когда и как нужно этот мусор убирать. Всё, что ты можешь сделать - следить, чтобы в коде не было "висячих" ссылок (ситуаций, когда объект тебе стал не нужен, но ссылка на него удерживается) - единственный источник утечек памяти в .NET.
1
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
27.03.2017, 18:07  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Это значит, что утечек нет
то есть, то что память не очищается ни сразу, ни через час - нормально?
0
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9674 / 4826 / 763
Регистрация: 17.04.2012
Сообщений: 9,664
Записей в блоге: 14
27.03.2017, 18:07
Цитата Сообщение от jr_ Посмотреть сообщение
вариант с _dataSource.Clear(); _dataSource = null; GC.Collect(); работает
А вариант
C#
1
2
_dataSource.Clear();
_dataSource = null;
работает?
Основной источник утечек в управляемом коде - неосвобождённые неуправляемые ресурсы (файлы, соединения с БД и т.д.)
1
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
27.03.2017, 18:13
Conditions for a garbage collection
Garbage collection occurs when one of the following conditions is true:
The system has low physical memory.
The memory that is used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs.
The GC.Collect method is called. In almost all cases, you do not have to call this method, because the garbage collector runs continuously. This method is primarily used for unique situations and testing.

Добавлено через 20 секунд
https://msdn.microsoft.com/en-... .110).aspx
1
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
27.03.2017, 18:17
Цитата Сообщение от jr_ Посмотреть сообщение
то есть, то что память не очищается ни сразу, ни через час - нормально?
Да. Это нормально. Условия, при которых начинается сборка мусора описаны в посте выше.

Добавлено через 1 минуту
Т.е. чаще всего сборка мусора начинается именно при выделении памяти под новые объекты. Нет создания новых объектов - нет и сборки мусора (это, если системе хватает памяти).
1
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
27.03.2017, 21:30  [ТС]
Цитата Сообщение от tezaurismosis Посмотреть сообщение
работает?
нет

Цикличное открытие-закрытие диалога(а каждое открытие влечет создание 20-30к объектов, + битмапы в них по мере их появления в таблице) постоянно увеличивает размер потребляемой памяти.
Но GC.Collect после обнуления очищает, вроде как, корректно.
0
Администратор
Эксперт .NET
 Аватар для tezaurismosis
9674 / 4826 / 763
Регистрация: 17.04.2012
Сообщений: 9,664
Записей в блоге: 14
28.03.2017, 05:47
Цитата Сообщение от jr_ Посмотреть сообщение
C#
8
_icon = _inner.Icon == null ? _empty : new Bitmap(new MemoryStream(_inner.Icon));
Bitmap который из System.Drawing?
Все созданные его экземпляры и экземпляры MemoryStream нужно освобождать. Используйте Dispose()
0
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
28.03.2017, 06:31
Цитата Сообщение от jr_ Посмотреть сообщение
а каждое открытие влечет создание 20-30к объектов, + битмапы в них по мере их появления в таблице
Неладно что-то в датском королевстве...

Графику можно было бы и кешировать. А 20-30К объектов... Такое количество точно нужно?
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
28.03.2017, 08:26  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Графику можно было бы и кешировать. А 20-30К объектов
в базе(хранится как Dictionary<int, BaseData>) столько позиций.
Для их отображения они оборачиваются в класс TableItem. Собственно обертки столько раз и создаются.
0
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
28.03.2017, 08:54
jr_, это очень плохое решение. 30К объектов каждый раз перезаворачивать... Может в коде представления добавить один класс-транслятор, без состояния, чем тридцать тысяч раз это делать?

Dictionary<int, BaseData> можно было бы заменить на OrderedDictionary<int, BaseData> - с целочисленными ключами оно будет быстрее работать.
1
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
28.03.2017, 10:14  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Может в коде представления добавить один класс-транслятор, без состояни
например?
0
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
28.03.2017, 10:34
jr_, насколько я понял из твоего кода, твой TableItem нужен был только для того, чтобы имя хранить для базового объекта и ссылку на него. Как вариант - сделать коллекцию-обёртку над исходными данными, и возвращать имя из индексатора основываясь на объекте по тому же индексу в базовой коллекции. И при выборе элемента, работать с коллекцией по индексу полученному в обработчике события.

Добавлено через 1 минуту
Т.е. просто прикинуться коллекцией строк для контрола, для которого данная коллекция выступает источником данных. При этом за основу будут браться оригинальные объекты, без дублирования и копирования.

Добавлено через 1 минуту
Это не решит проблему с якобы "утечками памяти", но существенно снизит её потребление настолько, что данная тема может даже стать неактуальной...
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
28.03.2017, 11:16  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Т.е. просто прикинуться коллекцией строк
Тогда бы хватило обычного select-a, но обертка хранит не только строковое имя. в примере она хранит name/id/icon. и она не единственная.

а еще проблема - контрол принимает в качестве источника данных коллекцию одного типа (а их может быть несколько, с разной иерархией наследования).
0
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
28.03.2017, 11:22
Цитата Сообщение от jr_ Посмотреть сообщение
в примере она хранит name/id/icon
Нет. В вашем примере - только Base и Name. Причём второе не используется, а первое используется только для коллекции выбранных элементов. Или я неправильно понял ваш код?

Цитата Сообщение от jr_ Посмотреть сообщение
а еще проблема - контрол принимает в качестве источника данных коллекцию одного типа (а их может быть несколько, с разной иерархией наследования).
Это не проблема, суррогат мог бы имитировать любой объект.
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
28.03.2017, 14:06  [ТС]
Цитата Сообщение от Usaga Посмотреть сообщение
Нет. В вашем примере - только Base и Name
там не Name, а Type - это поле, по которому контрол группирует строки в таблице(другого способа заставить его группировать столбцы не придумал пока, временное решение). этот класс еще одна обертка
что изначально было нужно - сделать диалог(в нём одна таблица), которая отображает элементы из любой коллекции данных.
очень сложно получилось, не спорю, думаю сейчас как бы упростить.

Цитата Сообщение от Usaga Посмотреть сообщение
При этом за основу будут браться оригинальные объекты, без дублирования и копирования
Если в коллекции, в которой будут лежать объекты разных типов такое не сработает, мне ведь отдавая придется создавать новый экземпляр, или я не правильно понял мысль?
0
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
28.03.2017, 14:24
Цитата Сообщение от jr_ Посмотреть сообщение
которая отображает элементы из любой коллекции данных.
Такое сложно сделать простым способом. Тут или рефлексия, или DataSet-ы использовать (а это опять дублирование данных).

Цитата Сообщение от jr_ Посмотреть сообщение
Если в коллекции, в которой будут лежать объекты разных типов такое не сработает, мне ведь отдавая придется создавать новый экземпляр, или я не правильно понял мысль?
Основная мысль с суррогатом для уменьшения дублирования - или вытаскивать данные из нижележащих объектов (тогда вообще красота, мы переиспользуем данные, не создаём лишний раз копии) или, генерировать их опираясь на эти объекты.

Второй вариант имеет смысл только, если запрашивается ограниченное количество записей из всех возможных (в этом случае, мы "заворачивам" только то, что было запрошено, по факту).

Добавлено через 5 минут
jr_, в общем, копайте в данном направлении, если получится.

Если вам действительно нужен "универсальный" DataGrid, то тут нужно смотреть в сторону DataSet-ов (суррогатных, естественно). Идея такая же: суррогат получает коллекцию чего-нибудь, рефлексией разбирается с тем, какие свойства и поля (публичные) есть у объектов в коллекции, "прикидывается", что содержит таблицу с теми же полями (чистое совпадение!) и выдаёт данные из "завёрнутой" коллекции под видом данных из этой таблицы.

Это всё должно проканать. Правда эти советы уже далеко ушли от основной темы.
1
Эксперт .NET
 Аватар для Usaga
14367 / 9468 / 1360
Регистрация: 21.01.2016
Сообщений: 35,726
28.03.2017, 14:30
В общем, глазами датагрида, ваша коллекция должна вести себя примерно так:
Миниатюры
Как справиться с утечкой памяти в коде?  
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.03.2017, 14:30

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

Что считать утечкой памяти?
class A { public: A() { cout &lt;&lt; &quot;create A&quot; &lt;&lt; endl; }; ~A() { cout &lt;&lt; &quot;delete A&quot; &lt;&lt; endl; }; void func(){ cout &lt;&lt; &quot;func A&quot; &lt;&lt;...

Является ли данный случай утечкой памяти?
Имеется программа, написанная на языке СИ с использованием граф. библиотеки GTK+. Запуск и наблюдения проводились на ноутбуке с 4гб...

Когда исправят баг с утечкой памяти в Rhythmbox?
В Ubuntu 12.04 x64 есть утечка памяти в Rhythmbox, мегабайт на 1 песню примерно... Исправлен ли этот баг в 12.10 x64? Есть у кого...

Как справиться GC
На хостинге с рельсовыми приложениями творится странное. Весят 74 метра, одна virtual memory занимают до 1g. Чем дольше работает...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
сукцессия 29. Переход от одних деревьев на другие делать более или менее вероятностным?
anaschu 12.07.2026
Насколько смена типов микоризы — исключительное событие в двухвековой сукцессии? Оценка вероятности в пространстве параметров В текущей версии модели успешно реализован ключевой механизм. . .
сукцессия 27. Думаю, как переделывать уже написанную статью с планами на сукцессию.
anaschu 12.07.2026
Анализ соответствия модели требованиям Реализованные компоненты: Механизм закисления почвы через протонную помпу Конкуренция между типами микориз pH как триггер сукцессии C/ P соотношение. . .
Сукцессия 26. Мат модель создана.
anaschu 12.07.2026
Модель смены растительных сукцессий посредством управления грибами работает внутри небольшой ячейки почвы, восстанавливающейся после пожара, где ненадолго бывшее царство хвойных снова захватили. . .
Решил проблему с ошибкой пагинации сообщений с сервера на алгоритме обхода дерева "Эстафета хвоста".
Hrethgir 12.07.2026
Проблема была в том, что удалялась именно новая кнопка, а не старая. Ни один ИИ не обнаружил это, а сам я смог только когда с работой стало попроще и когда заставил работать будущее автономное. . .
сукцессия 25. Хронология ошибок
anaschu 12.07.2026
# От 50-тонного гриба до устойчивого леса: хроника ошибок при построении модели вековой сукцессии микоризы ## О чём эта статья В процессе построения ОДУ-модели (система дифференциальных. . .
сукцессия 24. Промежуточное общее описание модели
anaschu 12.07.2026
Хендофф: модель АМ→ЭКМ сукцессии микоризы (ризосфера, 50 лет) Содержание проекта Симуляция вековой (50 лет) экологической сукцессии в почве леса Основные участники: АМ-гриб, ЭКМ-гриб,. . .
сукцессия 23. Более физиологичная физиология, более экологичная экология, более диффурные диффуры.
anaschu 12.07.2026
Что реально нашли и починили за эти 5 часов Правило Линдемана (КПД конверсии сахара в тело, kEff) — раньше 100% полученного углерода шло прямо в биомассу гриба; теперь только kEff=0. 5 (после. . .
сукцессия 22. От артефактов к физиологии: калибровка агентной модели грибной сукцессии для воспроизведения сезонной динамики и pH-плато
anaschu 11.07.2026
Аннотация В данной работе представлена калибровка агентной модели динамики грибных сообществ (fungal-succession), направленная на устранение нефизичных артефактов (коллапс биомассы, мгновенное. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru