Инфраструктура:
Железо: Виртуальная машина VMware на двух независимых ESXi с якобы живой и неповрежденной памятью
ОС: Microsoft Windows Server 2016 Standard (10.0.14393)
Процесс: Windows-служба x64 под .NET 4.5.2, запущенная под системной учёткой
Отсутствуют антивирусы и подозрительные драйверы.
Падения происходят раз в несколько дней. Традиционно для коррапта кучи — в произвольных местах, при обращении к памяти.
Проблема не поддаётся воспроизведению и стреляет у одного человека из десятков тысяч.
Поковырял WinDbg, куча действительно повреждена:
0:027> !VerifyHeap
object 0000021701b6f728: bad member 0000021701B7C9F8 at 0000021701B6F738
Last good object: 0000021701B6F710.
...
Could not request method table data for object 0000021701B7C9F8 (MethodTable: 39E70380864F9B7C).
Last good object: 0000021701B7C9D0.
Выяснил, что жертвой стали элементы одного из массивов:
> !DumpArray /d 0000021701942910
Name: RootNamespace.FileSession[]
MethodTable: 00007ff87d5d6de0
EEClass: 00007ff8d8498af0
Size: 272(0x110) bytes
Array: Rank 1, Number of elements 31, Type CLASS
Element Methodtable: 00007ff87b627750
[0] 0000021701bd0660
[1] 0000021701bd06a8
[2] 0000021701bd06f0
[3] 0000021701bd0738
> dq 0000021701942910
00000217`01942910 00007ff8`7d5d6de0 00000000`0000001f
00000217`01942920 00000217`01bd0660 00000217`01bd06a8
00000217`01942930 00000217`01bd06f0 00000217`01bd0738
00000217`01942940 00000217`01bd0780 00000217`01bd07c8
00000217`01942950 00000217`01bd0810 00000217`01bd0858
00000217`01942960 00000217`01bd08a0 00000217`01bd0900
00000217`01942970 00000217`01bd0948 00000217`01bd0990
00000217`01942980 00000217`01bd09d8 00000217`01bd0a20
Вначале идёт таблица методов, количество элементов (31 штука) и далее указатели на элементы массива.
...что мусор начинается имнно с того места, где раньше находился первый элемент массива.
Меня терзают смутные сомнения, что память, выделенная этому объекту была помечена, как незанятая и просто была переиспользована другим компонентом без каких-либо плясок с unsafe и выходом за границы буфера. Или GC попытался дефрагментировать память, и сделать ему это не удалось.
В связи с этим, у меня несколько вопросов:
1) На забугорных ресурсах кому-то помогает отключение параллелинга в GC
Если это не эффект плацебо, значит существуют какие-то гонки между потоками сборщика мусора, которые могут приводить к коррапту кучи? С чем они связаны? От чего зависят? ОС, окружение, железо?
2) Может ли на это как-то повлиять наличие или отсутствие флажка gcServer?
3) Как можно посмотреть — в какие захваченные регионы входит данный фрагмент памяти, кто его аллоцировал, кто держит (поимо !gcroot)?
Подозрительным является то, что "мусор" начинается ровно по границе массива. >_>
Ещё один камень в сторону GC. Другой дамп:
> !VerifyHeap
Could not request method table data for object 000001C88304B5E8 (MethodTable: C4C1934C7B7ABE70).
Last good object: 000001C88304B5C0.
> !objsize 000001C88304B5C0
sizeof(000001c88304b5c0) = 40 (0x28) bytes (System.String)
> db 000001C88304B5C0 L 40
000001c8`8304b5c0 98 de a8 d8 f8 7f 00 00-07 00 00 00 6d 00 6d 00 ............m.m.
000001c8`8304b5d0 2d 00 33 00 30 00 33 00-31 00 00 00 00 00 00 00 -.3.0.3.1.......
000001c8`8304b5e0 00 00 00 00 00 00 00 00-70 be 7a 7b 4c 93 c1 c4 ........p.z{L...
000001c8`8304b5f0 d3 5e e6 47 9c 83 18 2d-c4 8e d0 93 2d 49 4e 72 .^.G...-....-INr
> !gcroot 000001C88304B5C0
Found 0 unique roots (run '!GCRoot -all' to see all roots).
> !gcroot 000001C88304B5E8
Found 0 unique roots (run '!GCRoot -all' to see all roots).
Ready for finalization 0 objects (000001c8d0102cb0->000001c8d0102cb0)
Ссылок на эти объекты нет, в очереди финализатора их нет, зато есть мусор в чужой памяти.
Здравствуйте, Sharov, Вы писали:
S>Если никаких манипуляций с памятью через указатели не делается, то может просто на данной машине битая память? Т.е. проблема в железе.
Как я написал выше, это виртуальная машина, которую тестировали на двух разных железных серверах.
Вероятность того, что память битая на обоих крайне мала. Скорее у самих серверов бага в механизме работы с памятью.
Здравствуйте, Слава, Вы писали:
С>Пусть прогонят физический тест памяти. У них там ECC или самосбор?
Как я написал выше, это виртуальная машина, которую тестировали на двух разных железных серверах.
Вероятность того, что память битая на обоих крайне мала. Скорее у самих серверов бага в механизме работы с памятью. Но это не объясняет, почему проблема возникает только в нашем приложении.
LW>Как я написал выше, это виртуальная машина, которую тестировали на двух разных железных серверах. LW>Вероятность того, что память битая на обоих крайне мала. Скорее у самих серверов бага в механизме работы с памятью.
Виноват, невнимательно прочитал. Думал что на одной и той железке гоняли.
Здравствуйте, LWhisper, Вы писали:
LW>Всем привет, нужна помощь знающих камрадов.
LW>Проблема: LW>Корраптится куча, приложение падает.
Пробежался я по ответам. Мне ни один не понравился.
Кучу обычно портит либо кривой unmanaged, unsafe код или кривые Marshal-вызовы. Некий код "срёт" не в ту память и портит чужие данные а именно кучу. Пытался вспомнить короткий синоним к выражению "срёт в память" и пока не вспомнил
Это самое очевидное объяснение, если на разном железе одинаковое поведение.
Маловероятное объяснение — в винде можно грузить любую unmanaged dll во все процессы. Вот она и жжёт не по детски. Если у тебя один образ ВМ, то может и вдруг.
Что значит кораптица куча ?
У процесса есть 32/64 бита виртуального простраства, он же может туда клась что угодно и как угодно ?
”Жить стало лучше... но противнее. Люди которые ставят точку после слова лучше становятся сторонниками Путина, наши же сторонники делают акцент на слове противнее ( ложь, воровство, лицемерие, вражда )." (с) Борис Немцов
Здравствуйте, Aquilaware, Вы писали:
A>К слову, недавно в VMWare закрыли несколько подобных багов которые редко, но приводили к спонтанному разрушению памяти хоста и гостевой ОС. A>Если вы не используете PInvoke или ручную работу с памятью, то проблем быть не должно.
Используем, конечно.
Спасибо, посмотрим. Если под рукой есть ссылки — делись.
Здравствуйте, VladCore, Вы писали:
VC>Маловероятное объяснение — в винде можно грузить любую unmanaged dll во все процессы. Вот она и жжёт не по детски. Если у тебя один образ ВМ, то может и вдруг.
Данное объяснение более вероятно, как и повреждение файлов .NET Framework, так как проблема аффектит одного человека из сотен тысяч.
Здравствуйте, LWhisper, Вы писали:
LW>Всем привет, нужна помощь знающих камрадов.
LW>Проблема: LW>Корраптится куча, приложение падает.
Поделюсь мыслями на этот счет
1. Не стоит слишком доверять дампам и !VerifyHeap
потоки замораживаются в произвольный момент, GC может компактить кучу в это время, часть из них может что-то выделять, объекты могут быть не созданы до конца
стоит убедиться что ты не гоняешься за химерой
2. если есть подозрения на Unmanaged компоненты, как вариант есть
gcUnmanagedToManaged MDA gcUnmanagedToManaged MDA
он сильно тормозит, и только для дебага
3. Отловить все вызовы Marshsal.Copy через рефлектор или типа того. Нифига они не безопасные вопреки устоявшемуся мнению.
4. Если убитый объект находится в 0 поколении, скорее всего он убит вот только-только, надо смотреть стеки потоков, м.б. они еще не ушли от точки разрушения
5. еще вариант AppDomain.FirstChanceException, ловить accessviolation
+<configuration>
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true" />
</runtime>
</configuration>
O>Что значит кораптица куча ? O>У процесса есть 32/64 бита виртуального простраства, он же может туда клась что угодно и как угодно ?
В вопросе всё подробно описано.
Данные записываются поверх заголовков объектов, перетирая друг друга, как если бы данная область памяти считалась свободной.
Это может быть либо следствие прямого доступа к памяти и ошибке в алгоритме, косяка в системных запчастях, кривых драйверах, антивирусах или косяки железного сервера.
Здравствуйте, LWhisper, Вы писали:
LW>Здравствуйте, VladCore, Вы писали:
VC>>Маловероятное объяснение — в винде можно грузить любую unmanaged dll во все процессы. Вот она и жжёт не по детски. Если у тебя один образ ВМ, то может и вдруг.
LW>Данное объяснение более вероятно, как и повреждение файлов .NET Framework, так как проблема аффектит одного человека из сотен тысяч.
Прощу прощения еще раз, но с железом у данного человека все нормально? Разные виртуалки гоняли у данного клиента?
Здравствуйте, Sharov, Вы писали:
S>Прощу прощения еще раз, но с железом у данного человека все нормально? Разные виртуалки гоняли у данного клиента?
У клиента несколько железных серверов, на которых гоняли одну и ту же склонированную виртуалку. Вероятно, проблема либо в системом софте, либо в самой виртуалке или приложении, но не в железе.
Здравствуйте, rm822, Вы писали:
R>1. Не стоит слишком доверять дампам и !VerifyHeap R> потоки замораживаются в произвольный момент, GC может компактить кучу в это время, часть из них может что-то выделять, объекты могут быть не созданы до конца R> стоит убедиться что ты не гоняешься за химерой
Именно в этом и пытаюсь убедиться.
R>2. если есть подозрения на Unmanaged компоненты, как вариант есть R> gcUnmanagedToManaged MDA R> gcUnmanagedToManaged MDA R> он сильно тормозит, и только для дебага
Спасибо за наводку. Как я понимаю, это спровоцирует креш сразу после такого вызова?
R>3. Отловить все вызовы Marshsal.Copy через рефлектор или типа того. Нифига они не безопасные вопреки устоявшемуся мнению.
Проблема в том, что конфирмится у одного единственного человека из сотен тысяч.
R>4. Если убитый объект находится в 0 поколении, скорее всего он убит вот только-только, надо смотреть стеки потоков, м.б. они еще не ушли от точки разрушения
Увы, не нашёл.
R>5. еще вариант AppDomain.FirstChanceException, ловить accessviolation R>+<configuration> R> <runtime> R> <legacyCorruptedStateExceptionsPolicy enabled="true" /> R> </runtime> R></configuration>
К сожалению, это не просто досрочно убитые объекты, а объекты, на которые ещё есть ссылки. Поэтому мы отвалимся в будущем при работе с ними. Единственный вариант — выгрузить домен и запустить повторно, чего делать не хочется, пока проблема не будет ясна.
R>>3. Отловить все вызовы Marshsal.Copy через рефлектор или типа того. Нифига они не безопасные вопреки устоявшемуся мнению. LW>Проблема в том, что конфирмится у одного единственного человека из сотен тысяч.
А что за реальное железо у этого человека? Реальный проц какой?