Задать вопрос
@kodwi
https://moikrug.ru/kodwi

Почему приложение на C# съедает в 5 раз больше ожидаемого объема памяти?

Пишу приложение для работы с файлом определенной структуры, размер файла ~40 мб. Конфигурация для этого файла - XML файл ~ 650 кб. При открытии файла сначала считываю конфигурацию в XmlDocument, затем считываю байты каждого элемента из файла в List<>, связывая их с соответствующим элементом из конфигурации (т.е. считал байты элемента, создал для него объект самописного класса Element, куда записал эти байты и ссылку на соответствующий элементу XmlNode узел из конфигурации, затем добавил этот объект в List<>). Всего считывается примерно 4 - 4.2 кк элементов (40 мб). Как мне кажется, приложение должно отъедать максимум 70-80 мб оперативки (файл + ссылки на узлы конфигурации), но на деле выходит 300+ мб (в релизе). Код вроде не сложный, оптимизировать некуда. В чем может быть проблема?
  • Вопрос задан
  • 4916 просмотров
Подписаться 2 Оценить 1 комментарий
Решения вопроса 1
@asvishnyakov
Программист
1. List<> выделяет память кусками «про запас». Это называется capacity и отвечает за него одноимённое свойство. Если вы знаете, что ваш список в среднем будет содержать не больше N элементов, то это N нужно передать в соответствующий конструктор List<>.
2. Можно подсчитать байты и использовать выравнивание. Процесс трудоёмкий, но если сейчас много «пустого места», то в итоге вполне могут выйти желанные ~80МБ.
3. Ну и упомянутые утечки памяти. GC.Collect и memory profiling вам в помощь.

Ну а людям ноющим о медленности «управляемых» языков, больших DLL и 100 МБ памяти для .NET по-умолчанию и предлагающих перейти на другие языки, я предлагаю пойти поучиться у англоязычных коллег, которые не ноют по каждому случаю, а стараются действительно помочь разобраться в проблеме, в данном случае — увеличить производительность. Извините, накипело.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 6
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
А в чем проблема? Хотите точно знать сколько памяти будет использовать ваша программа - пишите на C.

Вы уверены что после разбора документа не остаются висеть какие-нибудь объекты? Может быть GC не отработал еще, может быть накладные расходы на маршалинг и прочее... Вообще как по мне не такой уж и большой оверхэд вышел.
Ответ написан
barkalov
@barkalov
Во "взрослой" студии есть анализ памяти - ANALIZE - Launch Perfomance Wizzard.
Возможно, течет через замыкания. Или сборщик не поспевает, попробуйте GC.Collect().
Ответ написан
Комментировать
Taraflex
@Taraflex
Ищу работу. Контакты в профиле.
Тут еще вопрос как именно вы определяете какой объем кушает прога?

Если код не сложный то я бы переписал прогу на D - синтаксически почти тот же C#, но позволяет работать на более низком уровне, возможно это вам могло бы помочь.
Ответ написан
Комментировать
vipuhoff
@vipuhoff
Для проверки повставляй в каждом месте, которое выполняется больше 100 раз GC.Collect() и посмотри что получилось, если памяти съедать стал меньше значит где то не успевает собираться мусор. Потом можно по одному убирать то что повставлял и смотреть после какого память снова начала расти, в том месте и разбирайся, что то в нем не так.
Ответ написан
Комментировать
Deerenaros
@Deerenaros
Программист, математик, задрот и даже чуть инженер
Ой, ой, страшно.

Ну сами подумайте, что такое C#? Это CIL. А рантайм CIL'а ой как память сжирает.

Вообще, это всё к недавнему вопросу здесь о том, что должен знать хороший программист. А знать он должен то, с чем работает. Если бы Вы знали, что C# - это "виртуальный" язык, то есть реальной машины, которая исполняла бы его код не существует. Он компилируется в тот самый CIL, который исполнятся виртуальной машиной. Она же сразу резервирует какую-то память, мегабайт сто-стопятьдесят, дабы быстро расположить в ней вновь создаваемые объекты. К тому же, подгружается несколько весьма больших DLL от которых "стандартно зависит" .NET-приложение.

Впрочем, и на Си контролировать память не так уж и просто. Как минимум будет пол-метра оверхеда, если не резать ножом. К слову, .NET тоже можно резать ножём, но так же эффективно, как Си, ясное дело, не получиться.
Ответ написан
Комментировать
aush
@aush
Возьмите WinDbg, подключите sos/psscor, снимите дамп да посмотрите, что за объекты у вас в памяти. Опыта тут большого не нужно, инфы по анализу .NET-памяти этим способом в инете полно.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы