Система.NET. OutOfMemoryException на Строке. Разделение () файла CSV на 120 МБ

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

Кроме того, KMS не рекомендует отправлять текстовые сообщения напрямую в KMS. Вместо этого они рекомендуют вместо этого использовать шифрование конвертов: используйте KMS для шифрования ключей данных и используйте эти ключи данных для шифрования ваших данных. Это не только приводит к гораздо меньшему количеству обращений к KMS в таких случаях, как ваше, но также создает разделение ресурсов: KMS никогда не имеет ваших зашифрованных данных и ключа, необходимого для их расшифровки.

Для вашего случая использования вы рассматривали возможность использования AWS Encryption SDK [1] [2]? Он обеспечивает простую в использовании реализацию шифрования конвертов и упрощает использование KMS для защиты ваших данных. Вы можете найти пример его настройки для использования KMS здесь [3] и пример шифрования и дешифрования файла здесь [4].

[1] https://docs.aws.amazon.com/encryption-sdk/latest/developer-guide/introduction.html

[2] https : //aws-encryption-sdk-python.readthedocs.io/en/stable/

[3] https://github.com/aws/aws-encryption-sdk- python / blob / master / examples / src / basic_encryption.py # L29

[4] https://github.com/aws/aws-encryption-sdk-python/blob/ ведущий / примеры / SRC / basic_file_encryption_with_multiple_providers.py # L96-L107

6
задан Craig W 30 April 2009 в 21:22
поделиться

9 ответов

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

Вы также должны знать, что, если вы не используете 64-битную Windows, ваша 4 ГБ ОЗУ разделена на 2 ГБ пространства ядра и 2 ГБ пространства пользователя, поэтому ваше приложение .NET не может получить доступ более 2 ГБ по умолчанию.

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

7
ответ дан 8 December 2019 в 04:31
поделиться

Не катите свой собственный парсер, если вам не нужно. Мне повезло с этим:

Быстрый CSV Reader

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

8
ответ дан 8 December 2019 в 04:31
поделиться

Если весь файл считан в строку, вам, вероятно, следует использовать StringReader .

StringReader reader = new StringReader(fileContents);
string line;
while ((line = reader.ReadLine()) != null) {
    // Process line
}

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

Редактировать после тестирования

Попытка выше с файлом 140 МБ, где обработка состояла из увеличения переменной длины с помощью line.Length. Это заняло около 1,6 секунд на моем компьютере. После этого я попытался сделать следующее:

System.IO.StreamReader reader = new StreamReader("D:\\test.txt");
long length = 0;
string line;
while ((line = reader.ReadLine()) != null)
    length += line.Length;

Результат составил около 1 секунды.

Конечно, ваш пробег может отличаться, особенно если вы читаете с сетевого диска или ваша обработка занимает достаточно много времени для поиска жесткого диска где-то еще. Но также, если вы используете FileStream для чтения файла и не буферизуете. StreamReader обеспечивает буферизацию, которая значительно улучшает чтение.

5
ответ дан 8 December 2019 в 04:31
поделиться

Как говорят другие авторы, OutOfMemory заключается в том, что он не может найти непрерывный кусок памяти запрошенного размера.

Тем не менее, вы говорите, что выполнение разбора строка за строкой было в несколько раз быстрее, чем чтение всего сразу и последующая обработка. Это имеет смысл, только если вы придерживались наивного подхода блокирования чтения, например (в псевдокоде):

while(! file.eof() )
{
    string line = file.ReadLine();
    ProcessLine(line);
}

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

1
ответ дан 8 December 2019 в 04:31
поделиться

Вам не хватает памяти в стеке, а не в куче.

Вы можете попробовать перефакторизовать ваше приложение так, чтобы обрабатывать ввод в более управляемых «порциях» данных, а не обрабатывать 120 МБ за один раз.

0
ответ дан 8 December 2019 в 04:31
поделиться

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

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

4
ответ дан 8 December 2019 в 04:31
поделиться

Вероятно, вам следует попробовать CLR-профилировщик , чтобы определить фактическое использование памяти. Возможно, существуют ограничения памяти, отличные от памяти вашей системы. Например, если это приложение IIS, ваша память ограничена пулами приложений.

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

0
ответ дан 8 December 2019 в 04:31
поделиться

Я согласен со всеми здесь, вам нужно использовать потоковую передачу.

Я не знаю, сказал ли кто-нибудь до сих пор, но вам стоит взглянуть на метод расширения.

И я точно знаю, что лучший метод разделения CSV на .NET / CLR - этот

Этот метод сгенерировал мне вывод XML +10 ГБ из входного CSV, включая расширенные входные фильтры и все такое, быстрее, чем все, что я видел.

0
ответ дан 8 December 2019 в 04:31
поделиться

Вы должны прочитать чанк в буфер и работать над ним. Затем прочитать другой кусок и так далее.

Существует множество библиотек, которые эффективно выполнят это за вас. Я использую одну из них под названием CsvHelper. Есть много крайних случаев, которые нужно обработать, например, когда запятая или конец строки находится в середине поля.

0
ответ дан 8 December 2019 в 04:31
поделиться
Другие вопросы по тегам:

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