При интеграции двух информационных баз 1С с использованием технологии COM разработчики часто сталкиваются с проблемой: данные успешно получены, но соединение продолжает висеть в списке активных сеансов целевой базы, удерживая лицензию и блокируя ресурсы. Разберем, как устроена работа со сборщиком мусора COM-объектов и как гарантированно отключиться от удаленной базы.
В платформе 1С:Предприятие не предусмотрено явного метода вроде Отключить() или ЗакрытьСоединение(). Физическое завершение сеанса происходит автоматически тогда, когда счетчик ссылок COM-объекта в операционной системе Windows становится равным нулю.
Проанализируем две ключевые причины, почему сеанс остается активным:
ВнешнийОбъект = Соединение.Справочники.Номенклатура.НайтиПоКоду("001");) и они не были очищены, сеанс не закроется.V83.COMConnector, остается в памяти (в глобальном модуле, реквизите формы или модуле сеанса), соединение помещается в системный пул и не разрывается.Рассмотрим правильный порядок очистки переменных в коде. Присвоение переменной пустой строки "" может приводить к неявным ошибкам приведения типов, поэтому эталонным способом в 1С является присвоение значения Неопределено.
Разберем по шагам правильный алгоритм работы с COM-соединением:
Посмотрим на пример безопасного кода с обработкой исключений:
COMКоннектор = Неопределено;
COMСоединение = Неопределено;
ВыборкаCOM = Неопределено;
Попытка
COMКоннектор = Новый COMОбъект("V83.COMConnector");
COMСоединение = COMКоннектор.Connect("Srvr=""Server1C"";Ref=""TargetBase"";Usr=""Admin"";Pwd=""Password"";");
// Выполняем действия в удаленной базе
Запрос = COMСоединение.NewObject("Запрос");
Запрос.Текст = "ВЫБРАТЬ Ссылка, Наименование ИЗ Справочник.Номенклатура";
ВыборкаCOM = Запрос.Выполнить().Выбрать();
Пока ВыборкаCOM.Следующий() Цикл
// Обработка данных
КонецЦикла;
Исключение
ЗаписьЖурналаРегистрации("COM-соединение", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
// Гарантированно освобождаем ресурсы
ВыборкаCOM = Неопределено;
COMСоединение = Неопределено;
COMКоннектор = Неопределено;
Наиболее надежный подход — инкапсулировать всю работу с внешним подключением внутри отдельной процедуры или функции без использования глобальных или экспортных переменных. Переменные, объявленные внутри процедуры, автоматически выходят из области видимости и уничтожаются сборщиком мусора при завершении работы процедуры.
Посмотрим на пример правильной изоляции контекста:
Функция ПолучитьКурсыВалютИзБазы(ПараметрыПодключения) Экспорт
Результат = Новый ТаблицаЗначений;
Коннектор = Новый COMОбъект("V83.COMConnector");
Соединение = Коннектор.Connect(ПараметрыПодключения);
// Получаем данные и переносим их в локальную таблицу значений
// Избегаем возврата наружу прямых COM-объектов
// При выходе из функции локальные переменные Коннектор и Соединение
// будут очищены платформой автоматически
Возврат Результат;
КонецФункции
Если для обхода разрядности (например, подключение из 64-битного сервера 1С к 32-битному COM-коннектору) используется серверное приложение COM+ в Windows, процесс dllhost.exe может удерживать соединение даже после обнуления всех переменных в коде 1С.
В этом случае сеанс закрывается только по истечении таймаута неактивности (Idle Timeout), настроенного в свойствах приложения в оснастке «Службы компонентов» (Component Services). Для минимизации простоя лицензий рекомендуется уменьшить время отключения приложения при простое до 1–2 минут.
Если требуется гарантированно и мгновенно разорвать сеанс на стороне целевой базы, можно воспользоваться административными инструментами платформы:
V83.COMAdmin и вызвать метод TerminateSession() у соответствующего кластера серверов.rac, взаимодействующую со службой ras целевого кластера.COM-соединение имеет существенные архитектурные ограничения:
comcntr.dll не работает на серверах под управлением Linux.Для современной и стабильной межсистемной интеграции рекомендуется заменять COM-соединения на: