Почему падает 1С при массовой выгрузке табличных документов со штрихкодами и как это исправить?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей IT и автоматизация бизнеса
← На главную

При выполнении групповой выгрузки или программного сохранения большого количества табличных документов (например, печатных форм «Реализация товаров и услуг» или «Счет-фактура») разработчики 1С часто сталкиваются с неожиданным аварийным завершением работы платформы. Процесс платформы прекращает работу без создания стандартного технического дампа, а в журналах событий Windows фиксируется сбой в модуле MSVCR90.dll.

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

Выясняем причину падения: лимит GDI-объектов в Windows

Проанализируем поведения системы в момент аварии. В операционной системе Windows для каждого процесса установлен жесткий пороговый лимит на количество одновременно используемых дескрипторов графического интерфейса (GDI-объектов) — по умолчанию это значение составляет 10 000 объектов.

Когда обработка 1С формирует печатную форму с динамическим графическим элементом (например, ActiveX-компонентой 1C BarCode), внутри процесса выделяются неуправляемые контексты устройств (DC), кисти, точечные рисунки и шрифты. Проблема заключается в том, что при очистке табличного документа на стороне 1С неуправляемые Win32-ресурсы не всегда освобождаются сразу.

Посмотрим, почему стандартные инструкции 1С не дают результата:

  1. Присвоение переменной значения ТабДок = Неопределено; освобождает только контекст объекта платформы 1С, но не вызывает моментальное удаление связанных с ним системных графических дескрипторов C++.
  2. Вызов метода ТабДок.Рисунки.Очистить(); также удаляет коллекцию рисунков из макета, но ActiveX-компонента или встроенная DLL может продолжать удерживать выделенные Win32 GDI-дескрипторы до завершения текущего потока или всего процесса.

Когда количество GDI-объектов процесса достигает 10 000, вызов функций Win32 API возвращает нулевой указатель (NULL). Библиотека C++ Runtime (MSVCR90.dll), не получив дескриптор, вызывает исключение Access Violation (0xC0000005). Из-за фатального характера этого исключения платформа 1С завершается мгновенно, не успевая записать технологический журнал или сформировать дамп.

Способ 1. Изоляция процессов выгрузки (дочерние сеансы)

Операционная система гарантированно и полностью очищает 100% GDI-объектов только при завершении процесса. Поэтому наиболее надежным программным архитектурным решением является вынос выгрузки пакетов документов в дочерние процессы.

Разберем по шагам реализацию разбиения выгрузки на порции:

  1. Основной сеанс 1С формирует список документов и делит его на пачки (например, по 200–500 документов).
  2. Для каждой пачки через COM-соединение (COMConnector) или через запуск отдельного дочернего экземпляра платформы в фоновом режиме выполняется процедура генерации и записи файлов.
  3. При закрытии дочернего COM-соединения или завершении фонового процесса Windows очищает все связанные GDI-ресурсы, после чего счетчик объектов сбрасывается.

Способ 2. Замена ActiveX-компоненты на штрихкодовый шрифт

Если штрихкод представляет собой стандарт EAN-13 или Code 39, целесообразно отказаться от использования внешней компоненты генерации штрихкода в пользу специализированного TrueType-шрифта (например, ean13.ttf).

Проанализируем преимущества этого подхода:

  1. Шрифт загружается операционной системой один раз для всей сессии и не создает динамических ActiveX-объектов при формировании каждой печатной формы.
  2. Табличный документ содержит обычный текстовый вывод со специальной контрольной суммой, что полностью исключает утечку GDI-дескрипторов.

Способ 3. Переход на компоненту Native API или сторонние библиотеки

Типовая компонента 1C BarCode старых версий (построена на базе ActiveX) создает отдельный элемент управления для каждого рисунка штрихкода. Использование альтернативных внешних компонент на базе технологии Native API решают данную проблему, так как они работают напрямую с буферами изображений без создания оконных Win32-элементов.

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


КартинкаШК = Новый Картинка(ПутьКФайлуИзображения);
ОбластьМакета = Макет.ПолучитьОбласть("Шапка");
Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = КартинкаШК;

Статические графические элементы Картинка не вызывают постоянного утекания ресурсов GDI в таких объемах, как ActiveX-контейнеры.

Способ 4. Временное увеличение лимита GDI-объектов в реестре Windows

Если изменить код или компоненту мгновенно невозможно, можно увеличить лимит GDI-объектов на уровне операционной системы Windows Server. Это позволит обработке успевать формировать значительно большее количество документов за один проход.

Рассмотрим пошаговое изменение параметра в реестре:

  1. Откройте редактор реестра regedit от имени администратора.
  2. Перейдите в раздел HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows.
  3. Найдите параметр GDIProcessHandleQuota. По умолчанию его значение в десятичной системе равно 10000.
  4. Увеличьте значение параметра до максимально допустимого — 65536 (десятичное).
  5. Перезагрузите сервер для применения изменений.

Важное замечание: данная настройка не устраняет саму утечку памяти, а лишь раздвигает границы допустимого количества объектов, позволяя обработать крупный пакет файлов без падения платформы.

← На главную