Многие администраторы и разработчики 1С сталкиваются с ситуацией, когда после нескольких динамических обновлений конфигурации (так называемого "демонического обновления") процесс rphost на сервере начинает занимать аномально много оперативной памяти. Нередко объем вырастает на несколько гигабайт за одно обновление. В этой статье мы подробно разберем причины такого поведения, проанализируем механизмы работы менеджера памяти сервера 1С и рассмотрим способы решения этой проблемы.
Для начала давайте разберемся, почему вообще происходит рост потребления памяти. Когда мы выполняем динамическое обновление, платформа не просто заменяет старый код новым. Процесс происходит сложнее:
rphost.Однако, даже когда все пользователи перезашли в программу, мы часто наблюдаем, что память не освобождается. Почему так происходит? Здесь в игру вступает работа менеджера памяти (аллокатора).
Сервер приложений 1С (как и многие высоконагруженные системы на C++) использует специфические менеджеры памяти. Главная особенность заключается в том, что процесс rphost захватывает память у операционной системы (ОС), но крайне неохотно возвращает ее обратно.
Мы можем выделить две основные проблемы:
Чтобы убедиться, как именно 1С работает с памятью и почему данные не удаляются мгновенно, мы можем провести эксперимент. Давайте создадим механизм, который заполняет память уникальными строками, а затем попытаемся отследить их наличие в памяти процесса.
Создадим процедуру заполнения регистра сведений тестовыми данными:
&НаСервере
Процедура FillНаСервере()
Набор = РегистрыСведений.РегистрСведений1.СоздатьНаборЗаписей();
Для Сч = 1 По 1000 Цикл
Запись = Набор.Добавить();
Запись.Измерение = Новый УникальныйИдентификатор;
// Создаем длинную уникальную строку для поиска в памяти
Запись.Ресурс = "TestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTestTest";
КонецЦикла;
Набор.Записать(Истина);
КонецПроцедуры
&НаКлиенте
Процедура Fill(Команда)
FillНаСервере();
КонецПроцедуры
Далее создадим процедуру чтения этих данных (чтобы они попали в кэш и оперативную память) и процедуру очистки:
&НаСервере
Процедура QueryНаСервере()
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РегистрСведений1.Измерение КАК Измерение,
| РегистрСведений1.Ресурс КАК Ресурс
|ИЗ
| РегистрСведений.РегистрСведений1 КАК РегистрСведений1";
Таблица = Запрос.Выполнить().Выгрузить();
КонецПроцедуры
&НаСервере
Процедура ClearНаСервере()
// Очищаем регистр
Набор = РегистрыСведений.РегистрСведений1.СоздатьНаборЗаписей();
Набор.Записать(Истина);
КонецПроцедуры
Суть эксперимента:
ClearНаСервере.Этот эксперимент доказывает, что 1С резервирует память и хранит там данные "про запас" или до момента перезаписи, что при частых динамических обновлениях приводит к раздуванию процесса rphost.
Поскольку мы выяснили, что память не возвращается автоматически из-за особенностей аллокатора и фрагментации, самым действенным методом является перезапуск рабочих процессов. Рассмотрим, как это сделать правильно.
В консоли администрирования кластера серверов 1С (или через утилиту rac) необходимо настроить параметры рабочих процессов. Это наиболее "цивилизованный" способ борьбы с утечками.
В свойствах рабочего сервера или кластера найдите настройки:
При таких настройках кластер сам будет отслеживать "раздувшиеся" после динамического обновления процессы rphost, запускать новые и плавно переводить на них пользователей, завершая старые процессы и освобождая память.
Если автоматическая настройка недоступна или нужно освободить память "здесь и сейчас", можно воспользоваться методом изменения интервала перезапуска:
60 (секунд) или другое малое значение.rphost, а старый перейдет в режим завершения.Этот метод форсирует создание чистого процесса, но может вызвать временное снижение производительности в момент переключения.
Еще одним способом минимизировать риски динамического обновления является использование расширений конфигурации. Обновление расширений технически отличается от обновления основной конфигурации.
Хотя обновление расширений также требует ресурсов и перестроения кэшей, оно считается более безопасным ("мягким"). Сервер накладывает расширение поверх основной структуры. Однако, стоит помнить, что даже при работе с расширениями память rphost может расти из-за необходимости кэшировать объединенную структуру метаданных. Поэтому настройки перезапуска рабочих процессов остаются актуальными и в этом случае.
Динамическое обновление действительно "съедает" память из-за дублирования версий метаданных и фрагментации кучи. Полностью избавиться от этого на уровне кода невозможно, так как это особенность работы менеджеров памяти C++ приложений. Эффективным решением является правильная настройка параметров кластера 1С для автоматической рециркуляции (перезапуска) рабочих процессов при превышении лимита памяти.