Возможные причины FileStream.Написать(), чтобы вызвать исключение OutOfMemoryException?

StackOverflow https://stackoverflow.com/questions/552828

Вопрос

У меня есть 10 потоков, записывающих тысячи маленьких буферов (по 16-30 байт каждый) в огромный файл в случайных позициях.Некоторые потоки генерируют исключение OutOfMemoryException в FileStream.Операция Write().

Что вызывает исключение OutOfMemoryException ?На что обратить внимание?

Я использую FileStream следующим образом (для каждого записанного элемента - этот код выполняется из 10 разных потоков):

using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite, BigBufferSizeInBytes, FileOptions.SequentialScan))
{
 ...
 fs.Write();
}

Я подозреваю, что все буферы, выделенные внутри FileStream, не освобождаются GC вовремя.Чего я не понимаю, так это почему среда CLR, вместо того чтобы выбрасывать, просто не запускает цикл GC и не освобождает все неиспользуемые буферы?

Нет правильного решения

Другие советы

Если десять потоков открывают файлы, как показывает ваш код, то одновременно у вас есть максимум десять нераспределенных объектов FileStream.Да, файловый поток делает имейте внутренний буфер, размер которого вы указываете с помощью "BigBufferSizeInBytes" в вашем коде.Не могли бы вы, пожалуйста, сообщить точную стоимость?Если это достаточно большое (например~100 МБ), то это вполне может быть источником проблемы.

По умолчанию (т.е.если вы не указываете число при построении), этот буфер равен 4 КБ, и это обычно подходит для большинства приложений.В общем, если вы действительно заботитесь о производительности записи на диск, то вы могли бы увеличить ее до пары 100 КБ, но не более.

Однако для вашего конкретного приложения это не имело бы особого смысла, поскольку указанный буфер никогда не будет содержать больше 16-30 байт, которые вы записываете в него перед удалением() объекта FileStream.

Чтобы ответить на ваш вопрос, исключение OutOfMemoryException выдается только тогда, когда запрошенная память не может быть выделена после был запущен GC.Опять же, если буфер действительно большой, то в системе может остаться достаточно памяти, просто не смежный кусок.Это происходит потому, что куча больших объектов никогда не уплотняется.

Я несколько раз напоминал людям об этом, но Куча больших объектов можете выдать это исключение довольно незаметно, когда, по-видимому, у вас мало доступной памяти или приложение работает нормально.

Я довольно часто сталкивался с этой проблемой, когда делал почти в точности то, что вы здесь описываете.

Вам нужно опубликовать больше своего кода, чтобы правильно ответить на этот вопрос.Тем не менее, я предполагаю, что это также может быть связано с потенциальной проблемой Хэллоуина (Жуткий Дуки) .

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

ОП!просто прокрутил и заметил "BigBufferSizeInBytes", я снова склоняюсь к куче больших объектов...

На вашем месте (а это чрезвычайно сложно из-за отсутствия контекста) я бы предоставил небольшую отправку "mbuf", куда вы копировали входящие и исходящие данные вместо того, чтобы разрешать всем вашим потокам disperate по отдельности считывать данные из вашего большого резервного массива...(т.е.трудно не вызвать неадекватное распределение с очень тонким синтаксисом кода).

Буферы обычно не выделяются внутри FileStream.Возможно, проблема в строке "запись тысяч маленьких буферов" - вы действительно это имеете в виду?Обычно вы повторно используете буфер много-много-много раз (т.е.при разных вызовах чтения / записи).

Кроме того - это один файл?Потокобезопасность одного потока файлов не гарантируется...так что, если вы не выполняете синхронизацию, ожидайте хаоса.

Вполне возможно, что эти ограничения возникают из-за базовой операционной системы, и что .NET Framework бессилен преодолеть такого рода ограничения.

Что я не могу вывести из вашего примера кода, так это то, открываете ли вы много таких объектов FileStream одновременно или открываете их очень быстро последовательно.Использование вами ключевого слова 'using' гарантирует, что файлы будут закрыты после fs.Вызов Write().Для закрытия файла не требуется цикла GC.

Класс FileStream действительно ориентирован на последовательный доступ на чтение / запись к файлам.Если вам нужно быстро выполнить запись в случайные местоположения в большом файле, возможно, вы захотите ознакомиться с использованием виртуального сопоставления файлов.

Обновить:Похоже, что сопоставление виртуальных файлов официально не будет поддерживаться в .NET до версии 4.0.Возможно, вы захотите ознакомиться со сторонними реализациями этой функциональности.

Дэйв

Я испытываю нечто подобное и задавался вопросом, определяли ли вы когда-нибудь корень своей проблемы?

Мой код выполняет довольно много копирования между файлами, передавая довольно много мегабайт между разными байтовыми файлами.Я заметил, что, хотя использование памяти процесса остается в разумных пределах, во время копирования выделение системной памяти увеличивается слишком сильно - намного больше, чем используется моим процессом.

Я отследил проблему вплоть до FileStream.Вызов Write () - когда эта строка удалена, использование памяти, похоже, идет так, как ожидалось.Мой BigBufferSizeInBytes установлен по умолчанию (4k), и я не вижу нигде, где они могли бы накапливаться...

Все, что вы обнаружили при рассмотрении вашей проблемы, будет принято с благодарностью!

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top