Довольно часто при переносе объемных баз, например, при выгрузке остатков и справочников из старой редакции 1С:Управление торговлей 10.3 в новую УТ 11 с использованием правил «Конвертации данных 2.0», мы сталкиваемся с аварийным завершением работы программы.
Разберем типичную ситуацию: вы сформировали правила обмена, запустили стандартную обработку «Универсальный обмен данными в формате XML», процесс идет несколько часов (часто оставляют на ночь), а утром программа 1С вылетает с сообщением: «Не хватает памяти». При этом на компьютере может быть установлено 12 Гб или даже больше оперативной памяти. Давайте подробно проанализируем причину этой проблемы и рассмотрим эффективные практические способы ее решения.
Для начала проанализируем парадокс, когда физической памяти на компьютере много, а 1С все равно жалуется на ее нехватку. Все кроется в архитектурных ограничениях и принципах работы платформы с форматом XML.
Если вы запускаете выгрузку локально в файловой базе или используете 32-битный толстый/тонкий клиент 1С (процесс 1cv8.exe), то операционная система Windows выделяет этому 32-битному процессу максимум 2 Гб адресного пространства. При формировании файла обмена программа 1С выстраивает в оперативной памяти DOM-модель (Document Object Model) XML-документа. Это означает, что данные не просто записываются на диск строчка за строчкой по мере формирования, а выстраивают огромную древовидную структуру узлов непосредственно в оперативной памяти.
Как показывает практика, готовый XML-файл обмена весом в 2,5 Гб в распакованном виде может потребовать от 10 до 15 Гб оперативной памяти для своей обработки платформой. Естественно, 32-битное приложение очень быстро упирается в свой лимит 2 Гб и аварийно закрывается.
Рассмотрим самый простой и безопасный способ — не пытаться поместить весь объем базы в один гигантский файл. Разделим выгрузку на логические этапы: сначала выгрузим только нормативно-справочную информацию (справочники Номенклатуры, Контрагентов и т.д.), а затем, отдельным файлом, документы ввода остатков.
У многих специалистов возникает закономерный вопрос: «Если мы отдельно загрузим сначала справочники, а потом документы остатков, не возникнет ли проблем с задвоением элементов?». Посмотрим на этот нюанс внимательнее.
Чтобы дублей при загрузке частями не возникло, необходимо правильно настроить синхронизацию в «Конвертации данных». Разберем по шагам, как это сделать:
При таких настройках, когда вы загрузите файл со справочниками в УТ 11, они создадутся с теми же уникальными идентификаторами (GUID), что и в УТ 10.3. Когда вы начнете загружать второй файл с остатками, система прочитает GUID контрагента или номенклатуры в документе, гарантированно найдет уже созданный на первом этапе объект в базе-приемнике и просто подставит ссылку на него. Задвоений при переносе остатков не произойдет.
Если раздельная выгрузка по каким-то причинам не подходит или файлы всё равно получаются слишком большими, проанализируем серверную инфраструктуру. Если у вас или вашего клиента имеется клиент-серверный вариант работы (например, связка СУБД PostgreSQL и Сервера 1С:Предприятие), мы можем обойти ограничение 32-битного клиента.
Убедитесь, что установлен 64-битный сервер 1С. Загрузите ваши правила обмена непосредственно в эту клиент-серверную базу и настройте выгрузку как регламентное задание (выполнение в фоне). В этом случае ресурсоемкий процесс формирования огромного XML-файла будет выполняться рабочим процессом сервера rphost.exe. 64-битный процесс сервера не имеет лимита в 2 Гб адресного пространства и сможет утилизировать всю доступную оперативную память сервера (например, все ваши 12 Гб), успешно завершив выгрузку единым файлом.
Рассмотрим еще один мощный механизм, который позволяет полностью отказаться от создания огромного промежуточного файла на жестком диске. В типовой обработке «Универсальный обмен данными в формате XML» на вкладке выгрузки можно выбрать режим прямого подключения к информационной базе-приемнику.
При использовании COM-соединения (через инициализацию объекта V83.ComConnector) алгоритм работы кардинально меняется. Данные из базы-источника считываются небольшими порциями, моментально сериализуются и передаются по COM-каналу прямо в базу-приемник, где сразу же записываются в СУБД. Память, которая была занята текущей порцией данных, тут же освобождается для следующей.
Этот подход навсегда решает проблему переполнения оперативной памяти. Единственный нюанс — процесс обмена напрямую через COM-соединение может занять больше времени по сравнению с классическим файловым обменом.
Проанализируем сами правила конвертации. Очень часто проблема нехватки памяти кроется не в платформе 1С, а в неоптимально спроектированных правилах в КД 2.0.
Избегайте излишней каскадной выгрузки: В Правилах Конвертации Свойств (ПКС) есть коварная настройка «Выгружать объект полностью». Если ею злоупотреблять, то при выгрузке одного небольшого документа остатков программа по цепочке начнет тянуть за ним весь договор, из договора — контрагента, из контрагента — все его контактные лица и банковские счета, а оттуда — банки. Это приводит к построению гигантского дерева объектов в оперативной памяти. Выгружайте справочники отдельными Правилами Выгрузки Данных (ПВД), а в документах выгружайте исключительно ссылки на эти справочники (свойства поиска), без каскадной выгрузки самих объектов.
Очистка кэша: Если вы пишете сложный код в обработчиках событий (например, «Перед выгрузкой данных»), где используете глобальные переменные, таблицы значений или массивы для кэширования, не забывайте их очищать. Иначе при долгой работе это приведет к классической «утечке памяти».
В качестве продвинутого метода рассмотрим доработку кода обработки для пакетной (порционной) выгрузки. Суть метода заключается в ведении счетчика объектов и принудительном разбиении одного файла на несколько.
Посмотрим на пример логики, которую можно встроить в процесс выгрузки:
// Пример логики ограничения порции данных при выгрузке
СчетчикВыгруженныхОбъектов = СчетчикВыгруженныхОбъектов + 1;
Если СчетчикВыгруженныхОбъектов >= ЛимитОбъектовВФайле Тогда
// Завершаем текущий XML документ
ЗавершитьЗаписьВФайлXML();
// Формируем новое имя файла
НомерТекущегоФайла = НомерТекущегоФайла + 1;
НовоеИмяФайла = БазовоеИмяФайла + "_" + Строка(НомерТекущегоФайла) + ".xml";
// Открываем новый файл для продолжения выгрузки
НачатьЗаписьВНовыйФайлXML(НовоеИмяФайла);
// Сбрасываем счетчик
СчетчикВыгруженныхОбъектов = 0;
КонецЕсли;
Реализовав такой механизм, система автоматически сформирует не один «неподъемный» файл на 4 Гб, а 10 аккуратных файлов по 400 Мб, которые платформа 1С загрузит без малейших проблем с памятью.
Используя предложенные методы в комплексе или выбрав наиболее подходящий для вашей инфраструктуры, вы гарантированно избавитесь от ошибки «Нехватка памяти» и сможете стабильно переносить любые объемы данных.