Мазмұнға өту
Tez Base

Разбор аварийных дампов 1С: почему они пустые по умолчанию и как читать их без WinDbg

· Жарияланды:

Мониторинг и журналы

Падает rphost. В каталоге сервера копятся файлы .mdmp, вы делаете всё по инструкции из популярных статей: ставите WinDbg (низкоуровневый отладчик Microsoft для разбора аварийных дампов), открываете дамп, выполняете !analyze -v и получаете в ответ короткое ERROR: Exception information not found. Ни кода ошибки, ни адреса сбоя, ни намёка, что пошло не так.

Скажу сразу, без интриги: так и будет, и дело не в ваших руках. Причина в настройке сбора дампов, и почти на каждом сервере 1С она стоит так, что разобрать по этим файлам ничего нельзя. Ниже - почему так, как за десять секунд понять, есть ли у вас хоть один пригодный дамп, как прочитать дамп средствами самой 1С без WinDbg, и что сделать, чтобы следующее падение было разбираемым.

Это полная техническая версия. Короткий диагностический разбор, только по официальным механизмам, у нас опубликован на Инфостарте; здесь - всё целиком, включая чтение двоичного формата дампа.

Материал на данных одной инсталляции: клиент-серверная, два узла кластера, платформа 8.3.27, Windows Server 2016, семь месяцев наблюдений, 354 собранных дампа.

Почему дамп пустой

В файле logcfg.xml сервера тип дампа по умолчанию нулевой:

<dump create="false" type="0" prntscrn="false"/>

На дефолтной настройке (type="0") эти дампы шли без потока ExceptionStream: ни кода ошибки, ни адреса сбоя, ни контекста нити. Из такого файла причину не достанет ни один инструмент, включая WinDbg, - он честно ответит, что записи об исключении нет, и будет прав.

Насколько это массово: из 310 читаемых дампов запись об исключении нашлась ровно в одном. Полгода сервер аккуратно складывал в каталог файлы, по которым невозможно понять, отчего он упал. Это не поломка, это настройка по умолчанию.

Но кое-что в файле есть всегда, даже при минимальном типе: список загруженных библиотек, счётчики памяти и число нитей. По этой части в большинстве случаев видно, чей код живёт внутри рабочего процесса и что там произошло с памятью. К ней мы ещё вернёмся, но сначала - как не тратить время на заведомо пустые файлы.

Где взять дампы

Файлы .mdmp пишутся туда, что задано в атрибуте location тега <dump> в logcfg.xml (каталог conf сервера, по умолчанию C:\Program Files\1cv8\conf\). Если location не задан или самого logcfg.xml нет, дампы всё равно складываются в рабочий каталог процесса. Быстрее всего найти их поиском по диску сервера:

Get-ChildItem C:\,D:\ -Recurse -Filter *.mdmp

Скопируйте нужные файлы на свою машину: разбирать их можно на клиенте, права серверной учётной записи не нужны.

Как за десять секунд понять, есть ли у вас пригодные дампы

Открывать файлы для этого не нужно, достаточно посмотреть на имена. Имя дампа устроено так:

rphost_8.3.27.1989_00000000_20260806160704_14720.mdmp
                   ^^^^^^^^ хеш сбоя нулевой - записи об исключении внутри НЕТ

rmngr_8.3.27.1989_6040bd55_20260520170945_6408.mdmp
                  ^^^^^^^^ хеш ненулевой - есть что читать

Восьмизначный шестнадцатеричный токен в имени - это хеш сбоя. Нулевой означает, что внутри пусто; ненулевой - что есть запись об исключении. На всех 354 файлах правило выполнилось без единого промаха: единственный файл с ненулевым хешем оказался единственным же файлом с потоком исключения.

Практический вывод: если во всём каталоге хеши нулевые - там нет ни одного пригодного для разбора дампа, и чинить надо logcfg.xml, а WinDbg тут вообще ни при чём.

Заодно поправлю частое заблуждение. Тот же восьмизначный hex многие принимают за PID. Это не PID. PID - последний числовой токен в имени (в примере это 14720), записан десятичным числом.

Три строки, чтобы следующее падение было разбираемым

Лечится это одним изменением в logcfg.xml - поднять тип дампа до полного:

<dump create="true" type="3" location="D:\1c-dumps"/>

При type="3" в дамп попадает и поток исключения, и контекст нити - то, ради чего вообще открывают дамп. Дальше можно ловить два-три падения и возвращать тип обратно.

Честно про цену. Дамп полного типа занимает столько же, сколько процесс держал памяти. При среднем 2,5-3 ГБ на процесс и двух десятках падений в месяц это порядка 50-60 ГБ в месяц, а один эпизод в наших данных дошёл до 41 ГБ разом. Поэтому location - на отдельный диск, а режим включать временно, под отлов, а не навсегда.

Два момента оставлю как открытые, потому что на своих данных не смог их закрыть до конца, а врать не хочу. Первый: атрибут create="false" стоял, а 354 файла при этом существовали - рабочая гипотеза, что он управляет дампами по обрабатываемым исключениям, а дамп при аварийном завершении пишется независимо. Второй: DumpCount по умолчанию равен 10, но файлов в каталоге куда больше, значит ограничение либо не применяется, либо задано иначе. Если у вас есть точная трактовка по ИТС - это будет полезно.

Как вообще не допускать падений

Это главная часть, и я делю её на три уровня честности: что работает гарантированно, что убирает класс причин, и что выглядит виноватым, но не доказано.

Работает гарантированно. Задайте в свойствах рабочего сервера “Максимальный объём памяти рабочих процессов” и “Безопасный расход памяти за один вызов”. Это не гипотеза: при 31 дампе выше 4 ГБ и рекорде 41 839 МБ лимит превращает аварию в управляемый перезапуск. Падение не исчезает, но перестаёт уносить чужие сеансы. Скорее всего, это же уберёт и большую часть пустышек, файлов нулевого размера: они пустые потому, что на запись дампа памяти уже не осталось.

Тут стоит объяснить, почему лимит важнее, чем кажется. Есть две цифры памяти, и их путают. Резидент (WorkingSet) - то, что процесс физически держит в оперативной памяти, это показывает диспетчер задач. Коммит (PrivateUsage) - то, что процесс попросил у системы и получил, независимо от того, вытеснено оно в подкачку или нет. В одном из наших дампов резидент был 379 МБ, а коммит - 1371 МБ, разница в 3,6 раза. Мониторинг, следящий за резидентом, роста просто не увидит. На другом разборе так и вышло: процесс прибавлял полгигабайта в сутки одиннадцать суток подряд, и заметили это только по коммиту - как снять наклон и что выставить в кластере. А падения по “не удалось выделить память” считаются по коммиту: когда общий лимит (ОЗУ плюс файл подкачки) исчерпан, отказ получает не тот, кто память съел, а тот, кто следующим попросил. Падают посторонние процессы, и по их дампам виновника не видно.

Убирает класс причин. Пятая часть всех падений в наших данных пришлась на 03:00, окно регламентных заданий, и ровно в этих дампах чаще всего встречались IFilter-компоненты (nlhtml.dll, offfilt.dll и подобные). Это библиотеки Windows для разбора вложений при обновлении полнотекстового индекса: чужой файл разбирается сторонним кодом прямо в адресном пространстве rphost, и повреждённое вложение роняет процесс так, что обработчик 1С этому помешать не может. Вынесите обновление полнотекстового индекса в отдельный рабочий процесс или ограничьте типы индексируемых файлов. И общий принцип: не тащите COM и .NET в серверный процесс без нужды, а внешние компоненты подключайте файлом с диска, а не из макета, тогда у них в следующем дампе будут имя и версия.

Выглядит виноватым, но не доказано, и я так и напишу. Среда .NET (clr.dll), WPF и безымянная распакованная компонента присутствовали в 99 % дампов обоих узлов. Соблазн сказать “вот кто их роняет” большой, но присутствие - это не причинность. Библиотека может быть загружена всегда и быть ни при чём. Единственное доказанное падение в наших данных - вообще не в .NET, а в платформенной библиотеке (о нём ниже). Поэтому честная формулировка - “вот кто живёт внутри вашего процесса и почему за этим стоит следить”, а не “вот кто виноват”.

Как читать дамп средствами 1С, без WinDbg

Здесь многие останавливаются, потому что думают, что нужен WinDbg и отладочные символы. Для триажа - понять, чей код в процессе и куда смотреть дальше - хватает средств самой 1С. Дамп в формате MINIDUMP это обычные двоичные данные с простой структурой:

Заголовок:  +0  сигнатура U32 = 'MDMP'  ·  +8 число потоков  ·  +12 адрес каталога
Каталог:    записи по 12 байт - тип потока U32, размер U32, смещение U32
Поток 3  ThreadList:  число нитей
Поток 4  ModuleList:  число модулей + записи по 108 байт (база, размер, имя, версия)
Поток 6  Exception:   код исключения (+8), адрес сбоя (+24)  - его-то и нет при type=0
Поток 7  SystemInfo:  архитектура, версия ОС
Поток 22 VmCounters:  PeakWorkingSet, WorkingSet, PrivateUsage (+72)

Прочитать сигнатуру и каталог потоков средствами встроенного языка - вот столько кода:

// заголовок - первые 32 байта; сигнатура по смещению 0 должна быть MDMP
Шапка = ПрочитатьОбласть(Чтец, 0, 32);
Если Шапка.ПрочитатьЦелое32(0) <> 1347241037 Тогда   // 'MDMP' как беззнаковое целое
    ВызватьИсключение "Это не minidump";
КонецЕсли;

ЗаписейКаталога = Шапка.ПрочитатьЦелое32(8);    // число потоков данных в файле
RvaКаталога     = Шапка.ПрочитатьЦелое32(12);   // где лежит каталог потоков

// каталог: записи по 12 байт - тип потока, размер, смещение
Каталог = ПрочитатьОбласть(Чтец, RvaКаталога, ЗаписейКаталога * 12);
Для Номер = 0 По ЗаписейКаталога - 1 Цикл
    Смещение  = Номер * 12;
    ТипПотока = Каталог.ПрочитатьЦелое32(Смещение);
    РазмерПотока = Каталог.ПрочитатьЦелое32(Смещение + 4);
    RvaПотока    = Каталог.ПрочитатьЦелое32(Смещение + 8);
    Сообщить("Поток " + ТипПотока + ", " + РазмерПотока + " байт");
КонецЦикла;

ПрочитатьОбласть - это чтение куска из буфера с проверкой границ (любой битый адрес превращается в “нет данных” по одному показателю, а не роняет разбор целиком). Дальше по каталогу видно, какие потоки в файле есть. Нет потока 6 - причину не назвать, и это ровно тот случай type="0", с которого мы начали. Есть поток 4 - читаем список модулей и по путям раскладываем их на “платформа 1С”, “Windows”, “среда .NET”, “сторонняя компонента”.

Пара граблей встроенного языка, на которых тут легко обжечься. ПрочитатьЦелое32 у платформы беззнаковое, и поле версии однажды вернулось как 2 700 191 635 - больше 2^31, так что знаковую интерпретацию надо разворачивать в беззнаковую. Имена модулей лежат как MINIDUMP_STRING (длина в байтах, дальше UTF-16LE) - читать их посимвольно на двух сотнях модулей в каждом из пятисот файлов нельзя, это миллионы вызовов; быстрый путь - ПолучитьСтрокуИзДвоичныхДанных(..., "UTF-16LE").

Единственный настоящий дамп. Тот самый файл с ненулевым хешем: процесс rmngr (менеджер кластера), код 0xC0000005 ACCESS_VIOLATION, чтение по адресу 0xFFFFFFFF, и упало это внутри платформенной библиотеки самой 1С. То есть лёг не рабочий процесс, а менеджер кластера, а с ним весь узел, со всеми базами и пользователями. Адрес 0xFFFFFFFF - классический признак работы с указателем, который уже не действителен. Вывод “упало в платформе” меняет адресата: это тот случай, когда обращаться надо именно в поддержку 1С, приложив этот файл, а не искать ошибку у себя в конфигурации. И это же лучший аргумент за смену типа сбора: один пригодный дамп дал больше, чем остальные 353 вместе взятые.

Шпаргалка: признак - диагноз - действие

Признак в дампеЧто значитЧто сделать
Хеш в имени нулевой, потока 6 нетЗаписи об исключении внутри нет, причину не назватьПоднимите type до 3 в logcfg.xml, поймайте два-три падения
Файл нулевого размераПроцесс завершился так аварийно, что дамп не дописался - обычно нехватка памятиЗадайте лимит памяти рабочих процессов; смотрите долю таких файлов как симптом
Коммит сильно выше резидентаПамять выделена и вытеснена в подкачку - утечка, которую мониторинг по резиденту не видитСледите за PrivateUsage, а не за WorkingSet
Максимум памяти в десятки ГБРоста памяти ничто не ограничиваетПоставьте “Максимальный объём памяти рабочих процессов”
Процесс - rmngr или ragentУпал не сеанс, а весь узел кластераРазбирайте в первую очередь; при падении в платформе - в поддержку 1С
Среда .NET и WPF почти в каждом дампеВ процесс затянут чужой управляемый код; вина не доказанаНайдите источник (Новый COMОбъект, ПодключитьВнешнююКомпоненту), компоненту - файлом с диска
Безымянная <guid>.tmp версии 0.0.0.0Внешняя компонента, распакованная из макета: ни имени, ни версииПодключайте компоненту по пути, чтобы в дампе были имя и версия
sqlncli11.dll в большинстве дамповПрямой доступ к СУБД через ADO мимо платформы, драйвер снят с поддержкиНайдите ADODB.Connection, замените на Microsoft OLE DB Driver for SQL Server
IFilter-библиотеки, пик падений ночьюПолнотекстовый индекс разбирает вложения сторонним кодом в rphostВынесите обновление индекса в отдельный процесс или ограничьте типы файлов

И маленький словарь кодов, которые встречаются в потоке 6 чаще всего:

0xC0000005  ACCESS_VIOLATION      обращение по недоступному адресу (чаще всего - битый указатель)
0xC00000FD  STACK_OVERFLOW        переполнение стека, обычно бесконечная рекурсия
0xC0000374  HEAP_CORRUPTION       повреждение кучи, часто чужой компонентой
0x80000003  BREAKPOINT            сработала точка останова / assert внутри библиотеки

Коротко

  1. Дампы по умолчанию снимаются минимальным типом - записи об ошибке в них нет, и WinDbg тут бессилен не по вашей вине.
  2. Проверьте logcfg.xml до следующего падения, иначе весь архив окажется бесполезным.
  3. Хеш в имени файла за десять секунд говорит, есть ли внутри что читать.
  4. Формат MINIDUMP читается средствами встроенного языка 1С, без WinDbg и отладочных символов - для триажа этого достаточно.
  5. Поставьте лимиты памяти рабочих процессов - это превращает аварию в перезапуск и заодно убирает пустышки.
  6. Считайте инциденты, а не файлы, и следите за коммитом, а не за резидентом.

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

Готовые обработки по теме

Разбирать двоичный формат руками каждый раз не нужно - но диагностика сервера и СУБД этим не заканчивается. Наши инструменты по соседней теме, все на Инфостарте:

Если сервер падает регулярно, а разбираться с дампами и памятью некому, мы делаем оптимизацию и диагностику 1С как услугу - от чтения дампов до настройки лимитов и разгрузки регламентных заданий.

Мұны сіздің орныңызға жөндей аламын

1С неге тежелетінінің нақты себебін және оның жұмысын қалай жылдамдатуға болатынын табамыз - жорамалмен емес, технологиялық журнал мен сұрау жоспарлары арқылы. Құжат өткізуді, есептер мен алмасуларды бірнеше есе жылдамдатамыз. Қазақстан мен ТМД бойынша қашықтан.

Құны
150 000 ₸-денжоба үшін; салықтарсыз; тегін аудиттен кейін тіркеледі
"ауыр" операциялар бойынша әдеттегі нәтиже
сағаттар → минуттар

Жазуға ерте ме? Өзіңіз өлшеп көріңіз

Чек-ап СУБД под 1С: 40+ проверок с вердиктом по каждой

Өңдеуді ашу

INFOSTART TECH EVENT 2026: конференция для 1с-специалистов. если собираетесь, регистрируйтесь по нашей ссылке. Регистрация →

Мұны да оқыңыз

Нейросеть для проверки кода 1С: как проверить её на своём коде до внедрения

Прежде чем отдавать нейросети ревью кода 1С, её стоит принять на своём коде: у нас одна и та же локальная модель нашла 11 дефектов из 13 на учебных процедурах и 0 из 5 на рабочих. Разбираем порядок приёмки: какие два числа считать, из чего собрать проверочный набор, как поднять стенд без интернета и по каким признакам видно, что замер врёт.

Технологический журнал 1С: как собрать данные о тормозах

План короткого сбора технологического журнала 1С: вопрос, события, окно наблюдения и проверка причины. Как отличить ожидание от выполнения.

Управляемая блокировка 1С не работает: шесть причин, по которым замок не ставится

В коде стоит БлокировкаДанных, ревью пройдено, а потерянные обновления и минусовые остатки продолжаются. Разбор таких историй почти всегда упирается в одно: замок, на который рассчитывали, не ставился вовсе - и платформа об этом не сообщала. Чек-лист из шести мест, где блокировка теряется молча: режим блокировок объекта, флаг в процедуре-обёртке, чужая короткая транзакция, разделяемый режим, проверка вне транзакции и включение снимка на чтение. С кодом, который можно сверить со своей конфигурацией за вечер.