При переносе больших объемов информации (десятков тысяч элементов справочников или документов) из конфигураций платформы 1С:Предприятие 7.7 в современные версии 1С:Предприятия 8 через обработку УниверсальныйОбменДаннымиXML разработчики часто сталкиваются с аварийным завершением процесса и системным сообщением «Недостаточно памяти». Разберем детально, почему возникает данная ошибка, как локализовать проблемные места в правилах обмена и какими способами организовать выгрузку данных по частям.
Проанализируем архитектурные особенности платформы 1С 7.7 и типовых механизмов выгрузки, приводящие к падению процесса:
v7plus.dll или системный парсер MSXML. При выгрузке формируется объектная модель документа (DOM), которая полностью удерживается в оперативной памяти до момента финальной записи файла на диск. Если выгружаются связанные структуры и десятки тысяч элементов, дерево XML переполняет доступное адресное пространство.Выясним причину падения на конкретном этапе. Для этого включим в обработке выгрузки флаг «Комментировать выгрузку объектов» и проанализируем, на каком именно элементе или алгоритме останавливается процесс.
Часто в типовых правилах в обработчике ПередВыгрузкой ПКО справочника «Контрагенты» вызывается процедура сбора статистики по взаиморасчетам:
Если Параметры.СтатистикаПоДоговорам_СортКонтрагент = -1 Тогда
СформироватьСтатистикуПоДоговорам();
КонецЕсли;
Данная процедура заполняет огромную таблицу значений по всей истории документов в базе для определения статуса контрагента (клиент, поставщик, прочее). На больших базах этот вызов приводит к исчерпанию памяти еще до начала записи XML-узлов.
Если детальный ретроспективный анализ операций не требуется или его можно выполнить постфактум в целевой базе, оптимизируем обработчик в правилах конвертации (Конвертация Данных):
0 вместо -1).
Если ТипЗначенияСтр(ВходящиеДанные) <> "СписокЗначений" Тогда
ВходящиеДанные = СоздатьОбъект("СписокЗначений");
КонецЕсли;
// Устанавливаем признаки взаимоотношений по умолчанию
ВходящиеДанные.Установить("Клиент", 1);
ВходящиеДанные.Установить("Поставщик", 1);
ВходящиеДанные.Установить("ПрочиеОтношения", 0);
Если справочник содержит десятки тысяч записей, наиболее надежный способ — разбить выгрузку на независимые порции. Разберем несколько вариантов фильтрации.
Добавим в обработку выгрузки (или передадим через параметры правил) числовые границы КодС и КодПо. В обработчике ПередВыгрузкой соответствующего ПКО пропишем отсечение элементов, не входящих в текущую порцию:
// Приводим строковый код 1С 7.7 к числу для сравнения диапазонов
ТекКод = Число(Источник.Код);
Если (ТекКод < КодС) Или (ТекКод > КодПо) Тогда
Отказ = 1;
КонецЕсли;
Посмотрим на пример выгрузки данных алфавитными блоками (например, от «А» до «Д» в первый файл, от «Е» до «К» во второй):
ПерваяБуква = Лев(НРег(СокрЛП(Источник.Наименование)), 1);
// Выгружаем только контрагентов на буквы от "а" до "ж"
Если (ПерваяБуква < "а") Или (ПерваяБуква > "ж") Тогда
Отказ = 1;
КонецЕсли;
Рассмотрим, как правильно организовать фильтрацию по иерархии в среде 1С 7.7 внутри обработчика ПВД или ПКО. В отличие от платформы 8.x, в 1С 7.7 проверка принадлежности группе выполняется через метод ПринадлежитГруппе() с передачей ссылки на объект:
СпрГруппа = СоздатьОбъект("Справочник.Контрагенты");
// Ищем группу по коду и проверяем, что найденный объект действительно является группой
Если (СпрГруппа.НайтиПоКоду("00000001") = 1) И (СпрГруппа.ЭтоГруппа() = 1) Тогда
Если Объект.ПринадлежитГруппе(СпрГруппа.ТекущийЭлемент()) = 0 Тогда
Отказ = 1;
КонецЕсли;
КонецЕсли;
// Исключаем помеченные на удаление элементы при необходимости
Если Объект.ПометкаУдаления() = 1 Тогда
Отказ = 1;
КонецЕсли;
Для запуска тяжелых разовых выгрузок на 64-разрядных операционных системах можно расширить лимит выделяемой 32-битному процессу памяти с 2 Гб до 3,5–3,8 Гб.
IMAGE_FILE_LARGE_ADDRESS_AWARE) для исполняемого файла 1cv7s.exe (или 1cv7.exe).Подведем итог правильной подготовки больших выгрузок из 1С 7.7: