Как исправить ошибку «Недостаточно памяти» при замене ссылок в документе «Расчет себестоимости» в 1С?

Программист 1С v8.3 (Обычные формы) Бухгалтерский учет Промышленность, строительство и АПК
← На главную

При выполнении обработки «Поиск и замена значений» в информационных базах с большим объемом данных (например, в 1С:УПП или 1С:Комплексная автоматизация) нередко возникает ошибка «Недостаточно памяти». Чаще всего сбой происходит при обработке регламентного документа РасчетСебестоимостиВыпуска или связанных с ним регистров накопления и бухгалтерии.

Проанализируем причины возникновения этой проблемы и разберем практические способы ее решения.

Почему возникает ошибка нехватки памяти

Выясним причину такого поведения платформы. В основе проблемы лежат два ключевых фактора:

  1. Архитектура наборов записей с отбором по регистратору. Для подчиненных регистратору регистров платформа 1С не поддерживает частичное чтение или порционную дозапись данных. Метод Прочитать() загружает в оперативную память все движения конкретного документа разом, а метод Записать() полностью перезаписывает всю таблицу движений документа. Если документ содержит сотни тысяч или миллионы строк, объем данных в оперативной памяти превышает допустимые пределы.
  2. Ограничение 32-разрядного клиента. В режиме обычного приложения (толстый клиент) типовые обработки с диска ИТС выполняются в памяти клиентского процесса 1cv8.exe. 32-битный процесс физически не может адресовать более 2–3 ГБ оперативной памяти, что приводит к аварийному завершению работы даже при наличии свободных ресурсов на сервере.
  3. Накладные расходы платформы при записи. При выполнении метода Записать() платформа выполняет проверку ссылочной целостности, вызывает обработчики событий модуля набора записей и обновляет таблицы итогов регистров, что требует значительного объема дополнительной памяти.

Решение 1. Перенос обработки на 64-разрядный сервер

Если база работает в клиент-серверном режиме под управлением 64-битного сервера 1С, ограничение памяти клиентского приложения можно обойти, выполнив замену ссылок целиком на стороне сервера в контексте фонового задания (процесс rphost.exe).

Разберем по шагам создание процедуры для вызова через серверный модуль:


Процедура ЗаменитьСсылкуВРегистреНаСервере(ИмяРегистра, РегистраторСсылка, СтараяСсылка, НоваяСсылка) Экспорт
    
    НаборЗаписей = РегистрыБухгалтерии[ИмяРегистра].СоздатьНаборЗаписей();
    НаборЗаписей.Отбор.Регистратор.Установить(РегистраторСсылка);
    
    // Отключаем обработчики событий для экономии памяти и ускорения
    НаборЗаписей.ОбменДанными.Загрузка = Истина;
    
    НаборЗаписей.Прочитать();
    
    БылиИзменения = Ложь;
    Для Каждого Запись Из НаборЗаписей Цикл
        // Проверяем субконто и измерения
        Если Запись.СубконтоДт.Номенклатура = СтараяСсылка Тогда
            Запись.СубконтоДт.Номенклатура = НоваяСсылка;
            БылиИзменения = Истина;
        КонецЕсли;
        
        Если Запись.СубконтоКт.Номенклатура = СтараяСсылка Тогда
            Запись.СубконтоКт.Номенклатура = НоваяСсылка;
            БылиИзменения = Истина;
        КонецЕсли;
    КонецЦикла;
    
    Если БылиИзменения Тогда
        НаборЗаписей.Записать();
    КонецЕсли;
    
КонецПроцедуры

Запуск такой процедуры через ФоновыеЗадания.Выполнить() позволяет выделить серверному процессу необходимый объем памяти без падения клиентского сеанса.

Решение 2. Замена в первичных документах и штатный перерасчет

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

  1. Выполняем замену ссылок номенклатуры во всех первичных документах расчетного месяца (ТребованиеНакладная, ОтчетПроизводстваЗаСмену, РеализацияТоваровУслуг, ПеремещениеТоваров).
  2. Отменяем проведение документа РасчетСебестоимостиВыпуска. При отмене проведения движения очищаются без перегрузки памяти.
  3. Перепроводим документ расчета себестоимости заново. Штатный алгоритм расчета формирует движения порциями по собственным внутренним таблицам и корректно заполняет аналитику с новыми ссылками.

Решение 3. Оптимизация записи набора и временное отключение итогов

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

Посмотрим на пример выполнения операции:


// 1. Отключаем использование итогов регистра перед тяжелой перезаписью
РегистрыНакопления.УчетЗатрат.УстановитьИспользованиеИтогов(Ложь);

Попытка
    Набор = РегистрыНакопления.УчетЗатрат.СоздатьНаборЗаписей();
    Набор.Отбор.Регистратор.Установить(ДокументСсылка);
    Набор.ОбменДанными.Загрузка = Истина;
    
    Набор.Прочитать();
    
    Для Каждого СтрокаНабора Из Набор Цикл
        Если СтрокаНабора.Номенклатура = СтараяСсылка Тогда
            СтрокаНабора.Номенклатура = НоваяСсылка;
        КонецЕсли;
    КонецЦикла;
    
    Набор.Записать();
    
Исключение
    // Включаем итоги обратно в случае ошибки
    РегистрыНакопления.УчетЗатрат.УстановитьИспользованиеИтогов(Истина);
    ВызватьИсключение;
КонецПопытки;

// 2. Включаем итоги обратно и выполняем их пересчет
РегистрыНакопления.УчетЗатрат.УстановитьИспользованиеИтогов(Истина);
РегистрыНакопления.УчетЗатрат.ПересчитатьИтоги();

Установка свойства ОбменДанными.Загрузка = Истина предотвращает запуск тяжелых прикладных проверок в модуле набора записей, а отключение итогов исключает параллельное обновление агрегатов в СУБД во время фиксации транзакции.

← На главную