При выполнении групповой выгрузки или программного сохранения большого количества табличных документов (например, печатных форм «Реализация товаров и услуг» или «Счет-фактура») разработчики 1С часто сталкиваются с неожиданным аварийным завершением работы платформы. Процесс платформы прекращает работу без создания стандартного технического дампа, а в журналах событий Windows фиксируется сбой в модуле MSVCR90.dll.
Рассмотрим подробно причины возникновения этой ошибки, механику исчерпания системных ресурсов и варианты решения проблемы.
Проанализируем поведения системы в момент аварии. В операционной системе Windows для каждого процесса установлен жесткий пороговый лимит на количество одновременно используемых дескрипторов графического интерфейса (GDI-объектов) — по умолчанию это значение составляет 10 000 объектов.
Когда обработка 1С формирует печатную форму с динамическим графическим элементом (например, ActiveX-компонентой 1C BarCode), внутри процесса выделяются неуправляемые контексты устройств (DC), кисти, точечные рисунки и шрифты. Проблема заключается в том, что при очистке табличного документа на стороне 1С неуправляемые Win32-ресурсы не всегда освобождаются сразу.
Посмотрим, почему стандартные инструкции 1С не дают результата:
ТабДок = Неопределено; освобождает только контекст объекта платформы 1С, но не вызывает моментальное удаление связанных с ним системных графических дескрипторов C++.ТабДок.Рисунки.Очистить(); также удаляет коллекцию рисунков из макета, но ActiveX-компонента или встроенная DLL может продолжать удерживать выделенные Win32 GDI-дескрипторы до завершения текущего потока или всего процесса.Когда количество GDI-объектов процесса достигает 10 000, вызов функций Win32 API возвращает нулевой указатель (NULL). Библиотека C++ Runtime (MSVCR90.dll), не получив дескриптор, вызывает исключение Access Violation (0xC0000005). Из-за фатального характера этого исключения платформа 1С завершается мгновенно, не успевая записать технологический журнал или сформировать дамп.
Операционная система гарантированно и полностью очищает 100% GDI-объектов только при завершении процесса. Поэтому наиболее надежным программным архитектурным решением является вынос выгрузки пакетов документов в дочерние процессы.
Разберем по шагам реализацию разбиения выгрузки на порции:
COMConnector) или через запуск отдельного дочернего экземпляра платформы в фоновом режиме выполняется процедура генерации и записи файлов.Если штрихкод представляет собой стандарт EAN-13 или Code 39, целесообразно отказаться от использования внешней компоненты генерации штрихкода в пользу специализированного TrueType-шрифта (например, ean13.ttf).
Проанализируем преимущества этого подхода:
Типовая компонента 1C BarCode старых версий (построена на базе ActiveX) создает отдельный элемент управления для каждого рисунка штрихкода. Использование альтернативных внешних компонент на базе технологии Native API решают данную проблему, так как они работают напрямую с буферами изображений без создания оконных Win32-элементов.
В качестве замены также можно использовать специализированные внешние библиотеки генерации штрихкодов, которые отдают готовое бинарное изображение в формате PNG или BMP. Картинка помещается в область табличного документа стандартным образом:
КартинкаШК = Новый Картинка(ПутьКФайлуИзображения);
ОбластьМакета = Макет.ПолучитьОбласть("Шапка");
Рисунок = ОбластьМакета.Рисунки.Добавить(ТипРисункаТабличногоДокумента.Картинка);
Рисунок.Картинка = КартинкаШК;
Статические графические элементы Картинка не вызывают постоянного утекания ресурсов GDI в таких объемах, как ActiveX-контейнеры.
Если изменить код или компоненту мгновенно невозможно, можно увеличить лимит GDI-объектов на уровне операционной системы Windows Server. Это позволит обработке успевать формировать значительно большее количество документов за один проход.
Рассмотрим пошаговое изменение параметра в реестре:
regedit от имени администратора.HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows.GDIProcessHandleQuota. По умолчанию его значение в десятичной системе равно 10000.65536 (десятичное).Важное замечание: данная настройка не устраняет саму утечку памяти, а лишь раздвигает границы допустимого количества объектов, позволяя обработать крупный пакет файлов без падения платформы.