Почему внешняя обработка не выгружается из памяти после закрытия формы в 1С?

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

Часто разработчики сталкиваются с ситуацией, когда при отладке внешней обработки изменения в коде не применяются без полного перезапуска сеанса 1С. Рассмотрим классический случай: вы открываете обработку, закрываете ее, вносите изменения в модуль, снова открываете в том же сеансе — а исполняется старый код. Проанализируем, почему это происходит и как правильно управлять памятью и экземплярами обработок.

Суть проблемы: механизм подсчета ссылок

В платформе 1С:Предприятие используется механизм подсчета ссылок для сборки мусора и управления памятью. Объект (например, экземпляр внешней обработки) удаляется из оперативной памяти только тогда, когда счетчик ссылок на него становится равным нулю.

Когда мы открываем внешнюю обработку через меню «Файл — Открыть», платформа создает в памяти объект ВнешняяОбработкаОбъект. Этот объект «знает» о своих формах, а каждая форма имеет скрытую ссылку на сам объект обработки. Если счетчик ссылок не обнуляется при закрытии формы, экземпляр обработки остается «живым». Платформа 1С оптимизирует работу: при повторном открытии того же файла она берет уже существующий в памяти скомпилированный модуль, игнорируя ваши изменения на диске.

Разберем пример с циклической ссылкой

Посмотрим на ситуацию, когда обработка имеет основную форму инициализации, которая программно открывает рабочую форму (АРМ) и закрывается сама. На рабочей форме при открытии выполняется следующий код:


Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)
    // ... логика инициализации ...
    
    ИДФормыАРМ = Строка(Новый УникальныйИдентификатор);
    НоваяСтрокаТЗИД = ТЗИДФорм.Добавить();
    НоваяСтрокаТЗИД.ВызовИз = ЭтаФорма; // Внимание на эту строку!
    НоваяСтрокаТЗИД.ИД = ИДФормыАРМ;
    
    ЭтаФорма.КлючУникальности = ИДФормыАРМ;
КонецПроцедуры

В этом коде кроется главная ошибка — создание циклической ссылки. Переменная ТЗИДФорм является реквизитом самой формы (Таблица Значений). Добавляя в нее строку и присваивая колонке ВызовИз значение ЭтаФорма, мы заставляем форму ссылаться на саму себя.

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

Способы решения проблемы

Разберем несколько способов, как гарантированно «придушить» экземпляр обработки и избежать утечек памяти.

  1. Устранение циклических ссылок. Никогда не сохраняйте ссылку ЭтаФорма в коллекции (Таблицы Значений, Структуры, Массивы), которые являются реквизитами этой же формы. Вместо ссылок используйте уникальные идентификаторы (строковое представление). Замените сохранение объекта на сохранение ID или строкового представления.
  2. Принудительная очистка коллекций. Хорошей практикой является явная очистка всех реквизитов-коллекций перед уничтожением формы. Добавьте в обработчик события ПриЗакрытии код очистки:

Процедура ПриЗакрытии()
    ТЗИДФорм.Очистить();
    // Очистка других коллекций, массивов и структур
КонецПроцедуры

Дополнительные причины зависания форм

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

1. Жесткая связь через Владельца. В обычном приложении свойство ВладелецФормы создает сильную связь между окнами. Если вы назначаете форму-владельца, а затем пытаетесь ее закрыть до закрытия подчиненной формы, логика освобождения памяти может нарушиться. Если прямой контроль не требуется, лучше использовать механизм оповещений (Оповестить и ОбработкаОповещения) для обмена данными между окнами, а свойство владельца оставить пустым.

2. Метод ПолучитьФорму без параметров. Если вы вызываете ПолучитьФорму("ИмяФормы") без указания уникального ключа и владельца, платформа может закэшировать эту форму внутри объекта обработки. Если форма была получена программно, но не открыта или не закрыта корректно, она будет держать объект в памяти.

3. Глобальные и экспортные переменные. Использование экспортных переменных в общих модулях, куда случайно была записана ссылка на форму или саму обработку. Пока вы не очистите эту глобальную переменную, экземпляр не будет уничтожен.

Итоги

Выясним главное правило отладки: если внешняя обработка не обновляет свой код без перезапуска конфигуратора и предприятия, проблема всегда кроется в зависании объекта в оперативной памяти. Внимательно проверяйте коллекции, реквизиты и таблицы значений на предмет хранения ссылок на саму форму (ЭтаФорма) или на объект обработки. Разрыв циклических связей при закрытии формы гарантирует корректную работу сборщика мусора и очистку кэша.

← На главную