Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.142.119.241] |
|
Сообщ.
#1
,
|
|
|
Ситуация такая: прога открывает файл, он может быть большим, допустим 300 Мб. Читает его в буфер, потом буфер анализирует (просто преобразует байты в числа и заполняет поля некой структуры) и все, потом он не нужен. Но проблема в том, что занятая память не освобождается. Обнуление ссылки и даже ручной вызов сборщика мусора не помогают.
В конце концов я закомментировал весь код, в котором используется буфер, но ничего не изменилось. Весь этот код находится внутри одной функции, но при выходе из нее память не отдается. Причем если сделать маленький проектик и туда поместить этот код, то ручной вызов мусорщика память таки освобождает. А в большом проекте нет. Из-за чего это может быть? Код всего проекта я конечно не могу сюда кинуть. Да и как остальной код может на что-то влиять, если буфер является локальной переменной в данной функции, которая сейчас содержит только этот код? BinaryReader binReader = new BinaryReader(File.Open(path, FileMode.Open)); FileInfo fileInfo = new FileInfo(path); byte[] buffer = binReader.ReadBytes((int)fileInfo.Length); // здесь был код, использующий буфер, но он закомментирован buffer = null; GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); При работе проги эта функция может вызываться неоднократно (по отношению к разным файлам) и в конце концов получаем OutOfMemoryException |
Сообщ.
#2
,
|
|
|
Может как-то так
using (FileStream fs = File.Open(... { BinaryReader binReader = new BinaryReader(fs... } |
Сообщ.
#3
,
|
|
|
В .NET с памятью все не просто. Тут есть пара намеков, как можно ускорить освобождение памяти. Использование using - один из них.
http://stackoverflow.com/questions/1852929...ry-cleanup-in-c |
Сообщ.
#4
,
|
|
|
Юзай PerfView, возможно остались где то ссылки на буффер твой.
|
Сообщ.
#5
,
|
|
|
Цитата Ataru @ Причем если сделать маленький проектик и туда поместить этот код, то ручной вызов мусорщика память таки освобождает. А в большом проекте нет. - Дорогой, вынеси мусор! - Сейчас, подземелье с корешами дочистим, и тогда вынесу Т.е. сборщик памяти проинформирован, что данная память больше не требуется. Но это вовсе не значит, что он вот прям сейчас всё бросит и пойдёт очищать. Как приводил пример один из столпов NET, в ситуации с бесконечно большой памятью ни сборка мусора, ни финализаторы никогда не будут исполнены - потому что не надо. |
Сообщ.
#6
,
|
|
|
Цитата Mr.Delphist @ Т.е. сборщик памяти проинформирован, что данная память больше не требуется. Но это вовсе не значит, что он вот прям сейчас всё бросит и пойдёт очищать. Как приводил пример один из столпов NET, в ситуации с бесконечно большой памятью ни сборка мусора, ни финализаторы никогда не будут исполнены - потому что не надо. Если бы память была бесконечно большая, то и вопроса бы не возникло. У меня на компе 4 гига, когда одна прога выжрала больше 1 гига, то как бы пора чистить, не? Свободной памяти в этот момент вообще нет, остальное занято виндой и другими программами. Добавлено Цитата jack128 @ Юзай PerfView, возможно остались где то ссылки на буффер твой. Где могут быть ссылки на буфер, который является локальной переменной в данной функции, весь код которой я привел? Ну binReader.Close() только забыл скопировать. Добавлено Цитата ter_nk_ @ Может как-то так using (FileStream fs = File.Open(... { BinaryReader binReader = new BinaryReader(fs... } Честно говоря поленился с using экспериментировать. Мне кажется не должно влиять. Проблема ведь в удалении буфера, а не потока. После операции чтения буфер с потоком уже никак не связан. И БинариРидер я у себя закрываю конечно, и ссылку на него обнулял, и Dispose вызывал, все это заменяет using. Ну и потом, раз в тестовой программке память очищается, значит дело не в приведенном коде, а в остальной части проекта. Но скинуть весь проект нет возможности, поэтому я скорее хотел спросить примерно в какую сторону копать. Но это ладно, с этим моментом я в итоге разобрался, просто сделал маленький буфер и читаю в него частями. Строго говоря надо было изначально так делать. Теперь у меня другое вылезло, тут уж вообще загадка. Есть модуль, экспортирующий данные. Ему передаются ссылки на несколько DataGridView, он перебирает строки и экспортирует их содержимое (в что и как - сейчас не важно). Оказалось, что этот модуль тоже отжирает память и не возвращает после всего. Опять я по максимуму все закомментировал и оказалось, что память жрется вот на этих строках. private void BuildDataRows(ref DataGridView dg) { for (int iRow = 0; iRow < dg.Rows.Count; ++iRow) { DataGridViewRow row = dg.Rows[iRow]; for (int iCol = 0; iCol < dg.Columns.Count; iCol++) { // тут все закомментировано } } } DataGridView там конечно очень большой. При отображении таблицы приходится с ним работать в виртуальном режиме, т.е. использовать методы dg_CellValueNeeded. Но почему при переборе строк он съедает всю память и как заставить его ее освободить? Он гигабайт может съесть при вот таком переборе строк и колонок нескольких больших таблиц... |
Сообщ.
#7
,
|
|
|
Цитата Ataru @ Где могут быть ссылки на буфер, который является локальной переменной в данной функции, весь код которой я привел? Ну binReader.Close() только забыл скопировать. Без понятия, я твой проект не щупал. Но PerfView всё покажет. |