При обработке файлов большого размера (от 400 МБ и выше) в файловых базах 1С пользователи и разработчики часто сталкиваются с ошибкой «Недостаточно памяти». При этом на сервере может быть установлено несколько десятков гигабайт оперативной памяти, а файл подкачки и жесткий диск имеют много свободного места. Выясним причину возникновения этой проблемы и подробно разберем варианты ее решения.
Проанализируем ситуацию, которая приводит к аварийному завершению работы процесса 1cv8c.exe. При считывании и передаче крупных файлов происходят следующие процессы:
1cv8c.exe доходит до отметки 2400–2450 МБ, платформа исчерпывает адресное пространство и аварийно завершает работу.ДвоичныеДанные или ХранилищеЗначения платформа создает несколько временных копий данных в оперативной памяти (для буферизации, преобразования в Base64 при вызовах между клиентом и сервером и помещения во временное хранилище). В итоге файл размером 500 МБ может потребовать свыше 2 ГБ ОЗУ.Рассмотрим самое простое и эффективное решение. Если вы работаете с 32-разрядным тонким или толстым клиентом, система неизбежно упрется в лимит оперативной памяти процесса.
1cv8c.exe x64). Это снимает жесткое ограничение в 2 ГБ на процесс и позволяет задействовать необходимый объем оперативной памяти сервера или терминала.Разберем вариант оптимизации программного кода, если файл обрабатывается средствами платформы. Вместо считывания всего файла целиком в объект ДвоичныеДанные применим потоковое чтение и запись частями (буферами):
ИмяВходногоФайла = "C:\Files\LargeFile.zip";
ИмяВыходногоФайла = "C:\Files\Copy_LargeFile.zip";
ПотокЧтения = Новый ФайловыйПоток(ИмяВходногоФайла, РежимОткрытияФайла.Открыть);
ПотокЗаписи = Новый ФайловыйПоток(ИмяВыходногоФайла, РежимОткрытияФайла.Создать);
ЧтениеДанных = Новый ЧтениеДанных(ПотокЧтения);
ЗаписьДанных = Новый ЗаписьДанных(ПотокЗаписи);
РазмерБуфера = 1048576; // 1 МБ
Пока НЕ ПотокЧтения.Конец() Цикл
ДвоичныеДанныеБуфера = ЧтениеДанных.Прочитать(РазмерБуфера);
ЗаписьДанных.ЗаписатьДвоичныеДанные(ДвоичныеДанныеБуфера);
КонецЦикла;
ЗаписьДанных.Закрыть();
ЧтениеДанных.Закрыть();
ПотокЗаписи.Закрыть();
ПотокЧтения.Закрыть();
Посмотрим на метод разбиения файла на части фиксированного размера. Если необходимо выгрузить или загрузить файл большого объема, разберем работу функций РазделитьФайл() и ОбъединитьФайлы():
// Разделение файла на фрагменты по 20 МБ
ИмяИсходногоФайла = "C:\Export\BigDataBase.bak";
КаталогЧастей = "C:\Export\TempParts\";
РазмерЧасти = 20 * 1024 * 1024; // 20 МБ
МассивФайловЧастей = РазделитьФайл(ИмяИсходногоФайла, РазмерЧасти, КаталогЧастей);
// Последовательная обработка частей или их передача по одной
// ...
// Последующее объединение частей обратно в один файл
ИмяИтоговогоФайла = "D:\Import\BigDataBase.bak";
ОбъединитьФайлы(МассивФайловЧастей, ИмяИтоговогоФайла);
В файловой базе данные хранятся в файле 1cd, имеющем лимит 4 ГБ на одну таблицу. Хранение крупных файлов непосредственно в базе данных приводит к быстрому разрастанию таблицы и перегрузке памяти при считывании LOB-полей.
Настроим хранение файлов в томах на диске через Библиотеку Стандартных Подсистем (БСП):
Проанализируем еще одну причину переполнения памяти при программной обработке: использование временного хранилища без его своевременной очистки. При циклическом переносе большого количества файлов оперативная память не успевает высвобождаться.
Для принудительного освобождения ресурсов очистим адресное пространство сразу после обработки файла:
// Очистка адресного пространства после работы с файлом
УдалитьИзВременногоХранилища(АдресФайлаВоВременномХранилище);
Применение комплекса этих мер позволяет полностью устранить ошибку «Недостаточно памяти» и обеспечить стабильную работу 1С с файлами любых объемов.