При выполнении обработки «Поиск и замена значений» в информационных базах с большим объемом данных (например, в 1С:УПП или 1С:Комплексная автоматизация) нередко возникает ошибка «Недостаточно памяти». Чаще всего сбой происходит при обработке регламентного документа РасчетСебестоимостиВыпуска или связанных с ним регистров накопления и бухгалтерии.
Проанализируем причины возникновения этой проблемы и разберем практические способы ее решения.
Выясним причину такого поведения платформы. В основе проблемы лежат два ключевых фактора:
Прочитать() загружает в оперативную память все движения конкретного документа разом, а метод Записать() полностью перезаписывает всю таблицу движений документа. Если документ содержит сотни тысяч или миллионы строк, объем данных в оперативной памяти превышает допустимые пределы.1cv8.exe. 32-битный процесс физически не может адресовать более 2–3 ГБ оперативной памяти, что приводит к аварийному завершению работы даже при наличии свободных ресурсов на сервере.Записать() платформа выполняет проверку ссылочной целостности, вызывает обработчики событий модуля набора записей и обновляет таблицы итогов регистров, что требует значительного объема дополнительной памяти.Если база работает в клиент-серверном режиме под управлением 64-битного сервера 1С, ограничение памяти клиентского приложения можно обойти, выполнив замену ссылок целиком на стороне сервера в контексте фонового задания (процесс rphost.exe).
Разберем по шагам создание процедуры для вызова через серверный модуль:
Процедура ЗаменитьСсылкуВРегистреНаСервере(ИмяРегистра, РегистраторСсылка, СтараяСсылка, НоваяСсылка) Экспорт
НаборЗаписей = РегистрыБухгалтерии[ИмяРегистра].СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Регистратор.Установить(РегистраторСсылка);
// Отключаем обработчики событий для экономии памяти и ускорения
НаборЗаписей.ОбменДанными.Загрузка = Истина;
НаборЗаписей.Прочитать();
БылиИзменения = Ложь;
Для Каждого Запись Из НаборЗаписей Цикл
// Проверяем субконто и измерения
Если Запись.СубконтоДт.Номенклатура = СтараяСсылка Тогда
Запись.СубконтоДт.Номенклатура = НоваяСсылка;
БылиИзменения = Истина;
КонецЕсли;
Если Запись.СубконтоКт.Номенклатура = СтараяСсылка Тогда
Запись.СубконтоКт.Номенклатура = НоваяСсылка;
БылиИзменения = Истина;
КонецЕсли;
КонецЦикла;
Если БылиИзменения Тогда
НаборЗаписей.Записать();
КонецЕсли;
КонецПроцедуры
Запуск такой процедуры через ФоновыеЗадания.Выполнить() позволяет выделить серверному процессу необходимый объем памяти без падения клиентского сеанса.
В большинстве типовых конфигураций документ РасчетСебестоимостиВыпуска не содержит исходных производственных данных, а лишь рассчитывает стоимость по цепочкам затрат. Поэтому наиболее безопасный и методически правильный путь выглядит следующим образом:
ТребованиеНакладная, ОтчетПроизводстваЗаСмену, РеализацияТоваровУслуг, ПеремещениеТоваров).РасчетСебестоимостиВыпуска. При отмене проведения движения очищаются без перегрузки памяти.Если перепроведение документа невозможно и требуется прямая модификация набора записей, снизим нагрузку на оперативную память с помощью временного отключения пересчета итогов.
Посмотрим на пример выполнения операции:
// 1. Отключаем использование итогов регистра перед тяжелой перезаписью
РегистрыНакопления.УчетЗатрат.УстановитьИспользованиеИтогов(Ложь);
Попытка
Набор = РегистрыНакопления.УчетЗатрат.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(ДокументСсылка);
Набор.ОбменДанными.Загрузка = Истина;
Набор.Прочитать();
Для Каждого СтрокаНабора Из Набор Цикл
Если СтрокаНабора.Номенклатура = СтараяСсылка Тогда
СтрокаНабора.Номенклатура = НоваяСсылка;
КонецЕсли;
КонецЦикла;
Набор.Записать();
Исключение
// Включаем итоги обратно в случае ошибки
РегистрыНакопления.УчетЗатрат.УстановитьИспользованиеИтогов(Истина);
ВызватьИсключение;
КонецПопытки;
// 2. Включаем итоги обратно и выполняем их пересчет
РегистрыНакопления.УчетЗатрат.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.УчетЗатрат.ПересчитатьИтоги();
Установка свойства ОбменДанными.Загрузка = Истина предотвращает запуск тяжелых прикладных проверок в модуле набора записей, а отключение итогов исключает параллельное обновление агрегатов в СУБД во время фиксации транзакции.