Часто в практике разработчика 1С возникает ситуация, когда при выполнении вполне обычного кода платформа внезапно закрывается (крашится). При этом в стандартном журнале регистрации 1С не остается никаких следов или сообщений об ошибке. Давайте подробно разберем такую ситуацию, проанализируем возможные причины и рассмотрим эффективные методы диагностики.
Представим задачу: после включения суммового учета по складам в конфигурации «1С:Бухгалтерия» появились зависшие суммы с плюсами и минусами по складам, при этом сводно по номенклатуре итог равен нулю. Для свертки этих остатков была написана следующая процедура:
&НаСервере
Процедура СверткаНаСервере()
Проводки = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Проводки.ОбменДанными.Загрузка = Истина;
Проводки.Отбор.Регистратор.Установить(ДокОперация);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ХозрасчетныйОстатки.Счет КАК Счет,
| ХозрасчетныйОстатки.Субконто1 КАК Субконто1,
| ХозрасчетныйОстатки.Субконто2 КАК Субконто2,
| ХозрасчетныйОстатки.Субконто3 КАК Субконто3,
| ХозрасчетныйОстатки.Организация КАК Организация,
| ХозрасчетныйОстатки.Подразделение КАК Подразделение,
| СУММА(ХозрасчетныйОстатки.СуммаОстаток) КАК СуммаОстаток,
| СУММА(ХозрасчетныйОстатки.КоличествоОстаток) КАК КоличествоОстаток,
| СУММА(ХозрасчетныйОстатки.СуммаНУОстаток) КАК СуммаНУОстаток,
| СУММА(ХозрасчетныйОстатки.СуммаПРОстаток) КАК СуммаПРОстаток,
| СУММА(ХозрасчетныйОстатки.СуммаВРОстаток) КАК СуммаВРОстаток
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Остатки(&Период, Счет В (&Счет10), , ) КАК ХозрасчетныйОстатки
|
|СГРУППИРОВАТЬ ПО
| ХозрасчетныйОстатки.Субконто1,
| ХозрасчетныйОстатки.Организация,
| ХозрасчетныйОстатки.Субконто2,
| ХозрасчетныйОстатки.Подразделение,
| ХозрасчетныйОстатки.Субконто3,
| ХозрасчетныйОстатки.Счет
|ИТОГИ ПО
| Счет,
| Субконто1";
Запрос.УстановитьПараметр("Период", НачалоДня(ДатаСвертки));
МассивСчетов = Новый Массив;
МассивСчетов.Добавить(ПланыСчетов.Хозрасчетный.СырьеИМатериалы);
// ... добавление других субсчетов 10 счета ...
Запрос.УстановитьПараметр("Счет10", МассивСчетов);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеСчет = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"Счет");
Пока ВыборкаДетальныеСчет.Следующий() Цикл
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(ВыборкаДетальныеСчет.Счет);
ВыборкаДетальныеНоменклатура = ВыборкаДетальныеСчет.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам,"Субконто1");
Пока ВыборкаДетальныеНоменклатура.Следующий() Цикл
Если (ВыборкаДетальныеНоменклатура.СуммаОстаток <> 0) ИЛИ (ВыборкаДетальныеНоменклатура.КоличествоОстаток <> 0) Тогда
Продолжить;
КонецЕсли;
ВыборкаДетальные = ВыборкаДетальныеНоменклатура.Выбрать();
Пока ВыборкаДетальные.Следующий() Цикл
НоваяПроводка = Проводки.Добавить();
НоваяПроводка.Период = ДокОперация.Дата;
НоваяПроводка.СчетКт = ПланыСчетов.Хозрасчетный.Вспомогательный;
НоваяПроводка.СчетДт = ВыборкаДетальные.Счет;
НоваяПроводка.Организация = ВыборкаДетальные.Организация;
НоваяПроводка.ПодразделениеДт = ВыборкаДетальные.Подразделение;
БухгалтерскийУчет.УстановитьСубконто(НоваяПроводка.СчетДт, НоваяПроводка.СубконтоДт, "Номенклатура", ВыборкаДетальные.Субконто1);
БухгалтерскийУчет.УстановитьСубконто(НоваяПроводка.СчетДт, НоваяПроводка.СубконтоДт, "Склады", ВыборкаДетальные.Субконто2);
БухгалтерскийУчет.УстановитьСубконто(НоваяПроводка.СчетДт, НоваяПроводка.СубконтоДт, "Партии", ВыборкаДетальные.Субконто3);
НоваяПроводка.Сумма = - ВыборкаДетальные.СуммаОстаток;
НоваяПроводка.СуммаВРДт = - ВыборкаДетальные.СуммаВРОстаток;
НоваяПроводка.СуммаПРДт = - ВыборкаДетальные.СуммаПРОстаток;
НоваяПроводка.СуммаНУДт = - ВыборкаДетальные.СуммаНУОстаток;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Проводки.Записать();
КонецПроцедуры
На первый взгляд, код абсолютно корректен. Однако почти сразу после запуска происходит аварийное завершение 1С. Тестирование и исправление (ТиИ) базы не помогает. Рассмотрим шаги, которые помогут нам выявить причину падения.
Когда цикл обрабатывает сотни тысяч записей, пройтись по всем шагам отладчиком (клавиша F11) физически невозможно. Если памяти не хватает, или проблема в конкретной «битой» ссылке, 1С вылетит, и мы не узнаем, на какой итерации это произошло.
Решение: Напишем свой собственный механизм логирования. На каждой итерации цикла перед формированием проводки будем записывать данные (например, номенклатуру или счет) во внешний текстовый или XML файл. Важно использовать метод Записать() для файла на каждой итерации. Когда 1С упадет, в файле останется последняя записанная строка — это и будет та самая проблемная запись (или момент переполнения памяти), на которой всё сломалось.
Возможно, при формировании десятков тысяч проводок в один набор записей Проводки банально заканчивается оперативная память на сервере или клиенте (переполнение стека). В результате платформа закрывается без предупреждений.
Решение: Записывайте проводки порциями. Вместо накопления огромного массива в оперативной памяти, делайте Проводки.Записать(Ложь) (чтобы дозаписывать, а не затирать) каждые 1000 или 5000 итераций, после чего очищайте набор или пересоздавайте его.
Если внутренние средства 1С молчат, обратимся к операционной системе. Откроем Журнал событий Windows (Event Viewer) и перейдем в раздел «Приложения». Найдем событие типа Application Error, совпадающее по времени с вылетом.
Там будет указан сбойный модуль (например, core83.dll) и код исключения. Код 0xc0000005 обычно означает нарушение прав доступа к памяти — это явный признак внутренней ошибки платформы или конфликта драйверов/антивируса.
Для глубокого анализа включим Технологический журнал 1С. Также при аварийном завершении платформа формирует файлы дампов с расширением .mdmp (ищите в папках профиля пользователя или на сервере 1С). Эти дампы можно отправить в техническую поддержку фирмы «1С», чтобы разработчики указали точное место падения в исходном коде C++ самой платформы.
Проанализируем структуру таблиц. Встроенное ТиИ не всегда всесильно. Попробуем выполнить следующие действия:
.dt и загрузить обратно в пустую базу. Это вызовет полную реструктуризацию таблиц СУБД, что часто решает скрытые проблемы с индексами.chdbfl.exe (находится в папке bin платформы).Очень часто (и в разбираемом нами примере это оказалось главной причиной) аварийное завершение связано с багами конкретного релиза платформы 1С. Автор темы опытным путем выяснил, что виновником была платформа версии 8.3.19.1351. Разработчики регулярно вносят изменения, и иногда они приводят к регрессионным ошибкам в механизмах запросов или работы с регистрами.
Также помните, что новые релизы платформы агрессивно борются с пиратством. Если 1С находит в системе следы старых эмуляторов защиты HASP, она может принудительно завершить работу процесса (часто вообще без окон с предупреждениями).
Если ваша обработка вызывает аварийное завершение работы 1С, действуйте последовательно: сначала исключите нехватку оперативной памяти (пишите данные порциями), затем локализуйте «битую» запись через запись лога в текстовый файл. Если данные корректны, очистите кэш и обязательно проверьте работу кода на другой версии платформы (более новой или проверенной стабильной). В большинстве случаев проблема кроется именно в самом релизе платформы.