Как отладить повреждение в управляемой куче

Моя программа выдает ошибку, которую не может обработать блоком catch(Exception e), а затем выдает сбой:

Нарушение прав доступа Исключение поврежденного состояния.

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

Код выполняется в фоновом потоке и время от времени дает сбой, что не может быть легко воспроизведено. Итак, я подключил WinDbg к процессу и получил следующий стек исключения:

000000001dabd8c8 000007feea129a1d [HelperMethodFrame: 000000001dabd8c8]
000000001dabda00 000007fee90cfce8 System.Text.StringBuilder.ExpandByABlock(Int32)
000000001dabda40 000007fee90cfba4 System.Text.StringBuilder.Append(Char*, Int32)
000000001dabdaa0 000007fee9102955 System.Text.StringBuilder.Append(System.String, Int32, Int32)
000000001dabdaf0 000007ff00bf5ce3 MineUtils.Common.Strings.Strings.Replace(System.String, System.String, System.String, Boolean, Boolean)
000000001dabdb90 000007ff00bf5a59 MineUtils.Common.Strings.Strings.RemoveSubstrings(System.String, System.String, System.String, Boolean) [D:\Programs\Visual Studio 2005 Projects\MineUtils.Common\Strings\Strings.Common-Main.cs @ 1481

WinDbg показывает, что это исключение произошло:

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 000007feea129a1d (clr!WKS::gc_heap::find_first_object+0x0000000000000092)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 0000000000003d80
Attempt to read from address 0000000000003d80

Я читал, что такие исключения можно обрабатывать с помощью атрибута метода [HandleProcessCorruptedStateExceptions], но почему это исключение возникает, если я использую только StringBuilder?

Это предыдущий анализ WinDbg (StringBuilder.ToString() вызывает исключение):

*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

FAULTING_IP:
clr!WKS::gc_heap::find_first_object+92
000007fe`ea129a1d f70100000080    test    dword ptr [rcx],80000000h

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)
ExceptionAddress: 000007feea129a1d (clr!WKS::gc_heap::find_first_object+0x0000000000000092)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000001
NumberParameters: 2
   Parameter[0]: 0000000000000000
   Parameter[1]: 0000000000001c98
Attempt to read from address 0000000000001c98

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_PARAMETER1:  0000000000000000

EXCEPTION_PARAMETER2:  0000000000001c98

READ_ADDRESS:  0000000000001c98

FOLLOWUP_IP:
clr!WKS::gc_heap::find_first_object+92
000007fe`ea129a1d f70100000080    test    dword ptr [rcx],80000000h

MOD_LIST: <ANALYSIS/>

NTGLOBALFLAG:  0

APPLICATION_VERIFIER_FLAGS:  0

MANAGED_STACK:
(TransitionMU)
000000001AB7DFC0 000007FEE90CFE07 mscorlib_ni!System.Text.StringBuilder.ToString()+0x27
000000001AB7E010 000007FF00C750A9 SgmlReaderDll!Sgml.Entity.ScanToken(System.Text.StringBuilder, System.String, Boolean)+0x169
000000001AB7E080 000007FF00C760E6 SgmlReaderDll!Sgml.SgmlDtd.ParseParameterEntity(System.String)+0xc6
000000001AB7E0F0 000007FF00C76FD8 SgmlReaderDll!Sgml.SgmlDtd.ParseModel(Char, Sgml.ContentModel)+0x298
000000001AB7E160 000007FF00C7701C SgmlReaderDll!Sgml.SgmlDtd.ParseModel(Char, Sgml.ContentModel)+0x2dc
000000001AB7E1D0 000007FF00C7701C SgmlReaderDll!Sgml.SgmlDtd.ParseModel(Char, Sgml.ContentModel)+0x2dc
000000001AB7E240 000007FF00C76BA5 SgmlReaderDll!Sgml.SgmlDtd.ParseContentModel(Char)+0x65
000000001AB7E290 000007FF00C763D7 SgmlReaderDll!Sgml.SgmlDtd.ParseElementDecl()+0xe7
000000001AB7E320 000007FF00C747A1 SgmlReaderDll!Sgml.SgmlDtd.Parse()+0xc1
000000001AB7E370 000007FF00C73EF5 SgmlReaderDll!Sgml.SgmlDtd.Parse(System.Uri, System.String, System.IO.TextReader, System.String, System.String, System.Xml.XmlNameTable)+0x175
000000001AB7E410 000007FF00C73B33 SgmlReaderDll!Sgml.SgmlReader.LazyLoadDtd(System.Uri)+0x163
000000001AB7E480 000007FF00C737B9 SgmlReaderDll!Sgml.SgmlReader.OpenInput()+0x19
000000001AB7E4E0 000007FF00C7334C SgmlReaderDll!Sgml.SgmlReader.Read()+0x1c
000000001AB7E530 000007FEE5983C4C System_Xml_ni!System.Xml.XmlLoader.Load(System.Xml.XmlDocument, System.Xml.XmlReader, Boolean)+0xac
000000001AB7E590 000007FEE5983730 System_Xml_ni!System.Xml.XmlDocument.Load(System.Xml.XmlReader)+0x90
...
000000001AB7F0A0 000007FEE97ED792 mscorlib_ni!System.Threading.Tasks.Task.Execute()+0x82
000000001AB7F100 000007FEE90A181C mscorlib_ni!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)+0xdc
000000001AB7F160 000007FEE97E7F95 mscorlib_ni!System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)+0x1b5
000000001AB7F1E0 000007FEE97E7D90 mscorlib_ni!System.Threading.Tasks.Task.ExecuteEntry(Boolean)+0xb0
000000001AB7F220 000007FEE90EBA83 mscorlib_ni!System.Threading.ThreadPoolWorkQueue.Dispatch()+0x193
000000001AB7F2C0 000007FEE90EB8D5 mscorlib_ni!System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()+0x35
(TransitionUM)

EXCEPTION_OBJECT: !pe 2a61228
Exception object: 0000000002a61228
Exception type:   System.ExecutionEngineException
Message:          <none>
InnerException:   <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131506

MANAGED_OBJECT_NAME:  System.ExecutionEngineException

MANAGED_STACK_COMMAND:  _EFN_StackTrace

LAST_CONTROL_TRANSFER:  from 000007feea12bce4 to 000007feea129a1d

ADDITIONAL_DEBUG_TEXT:  Followup set based on attribute [Is_ChosenCrashFollowupThread] from Frame:[0] on thread:[PSEUDO_THREAD]

FAULTING_THREAD:  ffffffffffffffff

DEFAULT_BUCKET_ID:  INVALID_POINTER_READ_CALL

PRIMARY_PROBLEM_CLASS:  INVALID_POINTER_READ_CALL

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_READ_WRONG_SYMBOLS_CALL__SYSTEM.EXECUTIONENGINEEXCEPTION

ОБНОВЛЕНО СНОВА

Вот стек исключения WinDbg после того, как я включил выгружаемую кучу:

 (1480.e84): Access violation - code c0000005 (first chance)
ntdll!ZwTerminateProcess+0xa:
00000000`77c415da c3              ret
0:023> !clrstack
OS Thread Id: 0xe84 (23)
Child SP         IP               Call Site
0000000037ded848 0000000077c415da [HelperMethodFrame: 0000000037ded848]
0000000037dedab0 000007fee9effd17 System.Text.StringBuilder.ToString()*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_64\mscorlib\8f7f691aa155c11216387cf3420d9d1b\mscorlib.ni.dll

0000000037dedb00 000007ff00cceae9 Sgml.Entity.ScanToken(System.Text.StringBuilder, System.String, Boolean)

0000000037dedb70 000007ff00cd19b2 Sgml.SgmlDtd.ParseAttDefault(Char, Sgml.AttDef)
0000000037dedbc0 000007ff00cd120b Sgml.SgmlDtd.ParseAttDef(Char)
0000000037dedc00 000007ff00cd1057 Sgml.SgmlDtd.ParseAttList(System.Collections.Generic.Dictionary`2<System.String,Sgml.AttDef>, Char)
0000000037dedc50 000007ff00cd10cd Sgml.SgmlDtd.ParseAttList(System.Collections.Generic.Dictionary`2<System.String,Sgml.AttDef>, Char)
0000000037dedca0 000007ff00cd0e9a Sgml.SgmlDtd.ParseAttList()
0000000037dedd10 000007ff00cce1f1 Sgml.SgmlDtd.Parse()
0000000037dedd60 000007ff00ccd945 Sgml.SgmlDtd.Parse(System.Uri, System.String, System.IO.TextReader, System.String, System.String, System.Xml.XmlNameTable)
0000000037dede00 000007ff00ccd582 Sgml.SgmlReader.LazyLoadDtd(System.Uri)
0000000037dede70 000007ff00ccd1f9 Sgml.SgmlReader.OpenInput()
0000000037deded0 000007ff00cccd8c Sgml.SgmlReader.Read()
0000000037dedf20 000007fee67b3bfc System.Xml.XmlLoader.Load(System.Xml.XmlDocument, System.Xml.XmlReader, Boolean)*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_64\System.Xml\8e4323f5bfb90be4621456033d8b404b\System.Xml.ni.dll
*** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v4.0.30319_64\System.Xml\8e4323f5bfb90be4621456033d8b404b\System.Xml.ni.dll

0000000037dedf80 000007fee67b36e0 System.Xml.XmlDocument.Load(System.Xml.XmlReader)
[deleted]
0000000037deea90 000007feea61d432 System.Threading.Tasks.Task.Execute()
0000000037deeaf0 000007fee9ed17ec System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
0000000037deeb50 000007feea617c35 System.Threading.Tasks.Task.ExecuteWithThreadLocal(System.Threading.Tasks.Task ByRef)
0000000037deebd0 000007feea617a30 System.Threading.Tasks.Task.ExecuteEntry(Boolean)
0000000037deec10 000007fee9f1b953 System.Threading.ThreadPoolWorkQueue.Dispatch()
0000000037deecb0 000007fee9f1b7a5 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
0000000037def310 000007feeae4dc54 [DebuggerU2MCatchHandlerFrame: 0000000037def310]
0:023> !verifyheap
-verify will only produce output if there are errors in the heap
The garbage collector data structures are not in a valid state for traversal.
It is either in the "plan phase," where objects are being moved around, or
we are at the initialization or shutdown of the gc heap. Commands related to
displaying, finding or traversing objects as well as gc heap segments may not
work properly. !dumpheap and !verifyheap may incorrectly complain of heap
consistency errors.
object 000000000e34caf8: bad member 000000001024b9a0 at 000000000e34cb08
curr_object:      000000000e34caf8
Last good object: 000000000e34cab0
----------------
0:023> !analyze
Last event: 1480.e84: Exit process 0:1480, code 80131506
  debugger time: Sun Sep 18 14:22:42.592 2011 (UTC + 1:00)
0:023> !analyze -v
Last event: 1480.e84: Exit process 0:1480, code 80131506
  debugger time: Sun Sep 18 14:22:42.592 2011 (UTC + 1:00)
0:023> .do e34cab0
          ^ Syntax error in '.do e34cab0'
0:023> !do e34cab0
Name:        System.String
MethodTable: 000007feea026870
EEClass:     000007fee9baed58
Size:        72(0x48) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String:      appliedFiltersContainer
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feea02c758  4000103        8         System.Int32  1 instance               23 m_stringLength
000007feea02b298  4000104        c          System.Char  1 instance               61 m_firstChar
000007feea026870  4000105       10        System.String  0   shared           static Empty
                                 >> Domain:Value  00000000021343a0:000000000db21420 <<
0:023> !do e34caf8
<Note: this object has an invalid CLASS field>
Name:        System.Reflection.RuntimeAssembly
MethodTable: 000007feea02a128
EEClass:     000007fee9baf968
Size:        48(0x30) bytes
File:        C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007feea9ef7f0  4000e14        8 ...solveEventHandler  0 instance 0000000000000000 _ModuleResolve
000007feea036338  4000e15       10 ...che.InternalCache  0 instance 000000001024b9a0 m_cachedData
000007feea0259c8  4000e16       18        System.Object  0 instance 000000000e3abd18 m_syncRoot
000007feea033450  4000e17       20        System.IntPtr  1 instance         37a95f10 m_assembly

Что это может быть?


person net_prog    schedule 15.08.2011    source источник
comment
У вас не должно быть такого исключения, но вы не показали нам свой код. Вам нужно опубликовать функцию Replace и, возможно, RemoveSubstring.   -  person Gabe    schedule 15.08.2011
comment
Возможно, у меня неверная интерпретация результатов WinDbg, но стек CLR указывает на эти методы, я опубликовал их источник.   -  person net_prog    schedule 15.08.2011
comment
Может я неправильно понял твой вопрос. Всегда ли происходит сбой в этом методе, или вы видели сбой только один раз?   -  person Gabe    schedule 15.08.2011
comment
Программа анализирует веб-страницы и дает сбой в разных местах, поскольку работает с многочисленными потоками, но всегда StringBuilder находится наверху стека. В прошлый раз, когда был метод StringBuilder.ToString (), который вызывал такое же исключение, теперь это StringBuilder.Append ().   -  person net_prog    schedule 16.08.2011
comment
На самом деле это сборщик мусора, который находится наверху стека. StringBuilder существует, потому что это то, что запускает сборщик мусора. Как указано ниже, ваша проблема заключается в повреждении кучи, которое обычно не вызвано фактическим сбоями кода.   -  person Gabe    schedule 16.08.2011
comment
Если ваш код сам по себе не вызывает неуправляемый код, вы можете проверить в базе знаний службы поддержки DevExpress, они действительно вызывают неуправляемый код и могут иметь ошибку.   -  person plodoc    schedule 24.08.2011
comment
Это очень похоже на то, что ваш неуправляемый код не был разработан для работы в многопоточной среде. Я предлагаю вам инкапсулировать все вызовы неуправляемого кода в lock {} блоках, чтобы к нему мог получить доступ только один поток. Этого все еще может быть недостаточно, поскольку код может требовать, чтобы к нему имел доступ только один поток, ever.   -  person John Saunders    schedule 23.10.2011
comment
Net_prog, удавалось ли когда-нибудь найти первопричину? Я знаю, что это было много лет назад, но, может быть, ты помнишь?   -  person Abel    schedule 16.11.2019


Ответы (2)


Недавно я столкнулся с управляемым повреждением кучи, что было для меня чем-то новым. Я был очень разочарован этим, и мне пришлось многому научиться, чтобы иметь возможность его отлаживать. Хочу поблагодарить Севу Титова, который дал мне правильное направление для старта. Его ответ был кратким и очень полезным. Я хочу регистрировать действия, которые я предпринял для устранения проблемы, для собственной справки. Возможно, это будет полезно для тех, кто в этом не разбирается.

Повреждение кучи отладки в .NET 4:

Как заподозрить повреждение кучи?

Вкратце:

  1. Приложение вылетает случайным образом, вне зависимости от примененного перехвата исключений, и даже проходит через «одеяла», такие как catch(Exception), которые, как предполагается, перехватывают все исключения.

  2. Изучение стека CLR в аварийных дампах приложения показывает, что сборщик мусора находится наверху стека:

    000000001dabd8c8 000007feea129a1d [**HelperMethodFrame**: 000000001dabd8c8]
    000000001dabda00 000007fee90cfce8 System.Text.StringBuilder.ExpandByABlock(Int32)
    000000001dabda40 000007fee90cfba4 System.Text.StringBuilder.Append(Char*, Int32)
    ...
    
    EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)
    ExceptionAddress: 000007feea129a1d (**clr!WKS::gc_heap**::find_first_object+0x0000000000000092)
       ExceptionCode: c0000005 (Access violation)
      ExceptionFlags: 00000000
    NumberParameters: 2
       Parameter[0]: 0000000000000000
       Parameter[1]: 0000000000003d80
    ...
    
  3. Стек CLR всегда показывает разные точки. Произошел ли сбой или отображаемый код явно не имеет значения, например, метод StringBuilder, который, как показано, вызывает исключение.

Для получения дополнительных сведений см. . Сбой сети: управляемое повреждение кучи при вызове неуправляемого кода.

Пошагово. Каждый следующий шаг используется, если предыдущий не помогает.

Шаг 1. Проверьте код.

Проверьте код на наличие небезопасного или собственного кода:

  1. Просмотрите код для операторов unsafe, DllImport.
  2. Загрузите .NET Reflector и используйте его для анализа сборок приложения на предмет PInvoke. Таким же образом проанализируйте сторонние сборки, которые использует приложение.

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

Шаг 2. Убедитесь, что это исключение поврежденного состояния может быть обнаружено.

Для обработки таких исключений необходимо украсить метод, содержащий оператор catch(Exception), атрибутом [HandleProcessCorruptedStateExceptions] или применить следующее в файле app.config:

<configuration>
    <runtime>
        <legacyCorruptedStateExceptionsPolicy enabled="true" />
    </runtime>
</configuration>

В случае, если исключение было успешно обнаружено, вы можете зарегистрировать его и изучить. Это означает, что это не проблема поврежденной кучи.

Поврежденные исключения кучи не могут быть обработаны вообще: HandleProcessCorruptedStateExceptions не работает.

Дополнительную информацию об исключениях поврежденного состояния см. На странице Все об исключениях поврежденного состояния в .NET4.

Шаг 3. Оперативная отладка.

На этом этапе мы отлаживаем сбойное приложение в производственной среде (или там, где мы можем воспроизвести сбой).

Загрузите Инструменты отладки для Windows с сайта Microsoft Windows SDK для Windows 7 и .NET Framework 4 (будет загружен веб-установщик, который позволит выбрать необходимые компоненты для установки - отметьте все компоненты). Он установит как 32-битную, так и 64-битную (если ваша система x64) версии необходимых инструментов отладки.

Здесь нужно знать, как прикрепить WinDbg к живому процессу, как делать аварийные дампы и исследовать их, как загружать расширение SOS в WinDbg (подробности можно найти в Google).

Включите помощники отладки:

  1. Запустите Application Verifier (C:\Program Files\Application Verifier - используйте требуемую версию, x86 или x64, в зависимости от режима компиляции исполняемого файла), добавьте туда свой исполняемый файл на левой панели и на правой панели отметьте один узел «Basics / Heaps». Сохраните изменения.

  2. Запустите помощник Global Flags (C:\Program Files\Debugging Tools for Windows\gflags.exe - снова выберите правильную редакцию, x86 или x64). После запуска Global Flags перейдите на вкладку «Файл изображения» и в верхнем текстовом поле введите имя исполняемого файла без каких-либо путей (например, «MyProgram.exe»). Затем нажмите клавишу Tab и установите следующие поля:

    • Enable heap tail checking
    • Включить проверку без кучи
    • Включить проверку параметров кучи
    • Включить проверку кучи при вызове
    • Отключить объединение кучи бесплатно
    • Включить кучу страниц
    • Включить тегирование кучи
    • Включить верификатор приложений
    • Отладчик (введите путь к установленному WinDbg в текстовом поле справа, например, C:\Program Files\Debugging Tools for Windows (x64)\windbg.exe -g).

    Для получения дополнительных сведений см. Повреждение кучи, часть 2.

  3. Перейдите в «Панель управления / Система и безопасность / Система» (или щелкните правой кнопкой мыши «Компьютер» в меню «Пуск» и выберите «Свойства». Там нажмите «Дополнительные параметры системы», в открывшемся диалоговом окне перейдите на вкладку «Дополнительно» и нажмите кнопку «Переменные среды». В открывшемся диалоговом окне добавьте новую системную переменную (если вы системный администратор - в противном случае - пользовательскую переменную - в этом случае вам необходимо выйти / войти в систему). Требуемая переменная - «COMPLUS_HeapVerify» со значением "1". Более подробную информацию можно найти в вопросе о переполнении стека . NET / C #: Как установить переменную среды отладки COMPLUS_HeapVerify?.

Теперь мы готовы приступить к отладке. Запустите приложение. WinDbg должен запуститься для этого автоматически. Оставьте приложение запущенным, пока оно не выйдет из WinDgb, а затем изучите дамп.

СОВЕТ. Чтобы быстро удалить глобальные флаги, Application Verifier и настройки вложения отладчика, удалите в реестре следующий раздел: x64 - HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\*YourAppName*

Шаг 4. Включите MDA.

Попробуйте использовать помощников по управляемой отладке. Подробности см. В вопросе о переполнении стека What MDA полезны для отслеживания повреждения кучи?.

MDA необходимо использовать вместе с WinDbg. Я использовал их даже вместе с Global Flags и Application Verifier.

Шаг 5. Включите GCStress.

Использование GCStress - крайний вариант, потому что приложение становится практически непригодным для использования, но это все еще путь. Подробнее см. GCStress: как включить в Windows 7 ?.

Шаг 6. Скомпилируйте для x86.

Если ваше приложение в настоящее время компилируется для платформы «Any CPU» или «x64», попробуйте скомпилировать его для «x86», если для вас нет разницы, какую платформу использовать. Я видел, как это сообщается, чтобы решить проблему для кого-то.

Шаг 7. Отключите параллельный сборщик мусора - у меня это сработало

Сообщается об известной проблеме в .NET 4, о которой сообщается в потоке Нарушение прав доступа в среде выполнения .NET 4 в gc_heap :: garbage_collect без неуправляемых модулей. Проблему можно решить, отключив параллельный сборщик мусора в файле app.config:

<?xml version="1.0"?>
<configuration>
    <runtime>
        <gcConcurrent enabled="false" />
    </runtime>
</configuration>
person net_prog    schedule 17.10.2011

Вы справились с кучей порчи. Найти основную причину проблемы повреждения управляемой кучи непросто, поскольку проблема обычно проявляется спустя долгое время после повреждения кучи. В вашем случае StringBuilder - отвлекающий маневр. Коррупция случилась раньше.

Я бы сделал следующее:

  1. Проверьте, есть ли у вас небезопасный код C #. Если они у вас есть, дважды проверьте там логику.
  2. Включите страничную кучу для своего приложения. Запуск его со страничной кучей поможет выявить проблемы с неуправляемым кодом - в случае, если неуправляемый код повреждает управляемую кучу.
  3. Запускаем !VerifyHeap в разных местах. Таким образом вы сможете локализовать место в коде, где происходит повреждение.
  4. Если для вашего приложения включен серверный тип сборки мусора, временно измените его на сборку мусора на рабочей станции - таким образом вы получите более предсказуемое поведение.
  5. Прочтите сообщение в блоге Tesses . Сбой .NET: управляемое повреждение кучи при вызове неуправляемого кода. Он демонстрирует некоторые примеры управляемого повреждения кучи.

Обратите внимание: когда вы будете запускать свой код под WinDbg, вы будете время от времени сталкиваться с первым шансом AV. Это безопасно: просто введите sxd av после того, как подключите WinDbg к процессу, и исследуйте только второстепенные антивирусные программы.

person seva titov    schedule 16.08.2011
comment
У меня есть еще один аварийный стек после включенной страничной кучи, теперь он указывает на другой код, не могли бы вы взглянуть. ! VerifyHeap на этот раз ничего не дал. - person net_prog; 22.08.2011
comment
@net_prog, это был второй шанс AV на этот раз? Вам нужно только посмотреть на антивирусные программы второго шанса на предмет повреждения кучи. Если! VerifyHeap не сообщает о повреждении, это означает, что с кучей все еще в порядке, и вы столкнулись с другой проблемой, а не с повреждением кучи. - person seva titov; 22.08.2011
comment
Полагаю, это был первый шанс: (f24.103c): Нарушение прав доступа - код c0000005 (первый шанс), и я больше не смотрел, выйдет ли программа, я просто остановил отладку. Мне придется подождать еще одного сбоя, чтобы узнать подробности. - person net_prog; 23.08.2011
comment
Я включил сборщик мусора для рабочей станции, и, похоже, он работал нормально больше недели, затем я удалил сборщик мусора для рабочей станции и получил еще один сбой, я обновил первый пост, это было первое случайное исключение, которое привело к завершению программы, и в куче были ошибки как написано в посте обновления. К сожалению, Pageheap не показала истинную причину проблемы, снова указывает на StringBuilder. Что еще я могу сделать? - person net_prog; 18.09.2011
comment
Как это должно выглядеть, когда Pageheap вызывает исключение? Всегда ли это исключение для второго шанса? Есть ли оператор завершения программы после исключения? В моем последнем случае это было исключение первого случая, которое привело к завершению программы и включению Pageheap, что это могло означать? - person net_prog; 18.09.2011
comment
В большинстве случаев, когда я сталкивался с кучей страниц, это всегда вызывало второй шанс AV. Однако я мог легко представить, что до второго изменения AV может не добраться. Это может произойти, если: а) существует явный catch (...) обработчик для всех исключений; и б) приложение считает, что оно намного умнее ОС, и проглатывает исключения, которых не должно. В хорошо написанных приложениях, если вы не знаете, как восстановить исключение, вы должны передать его в ОС (и отладчик, если он подключен). - person seva titov; 18.09.2011
comment
Да, я перехватываю все исключения в фоновых потоках, чтобы регистрировать их. Однако это исключение повреждения кучи предотвращает выполнение кода перехвата. Разве такое глотание мешает мне найти причину проблемы? Даже с PageHeap он указывает на StringBuilder. Я только что проверил, и этот код не использует небезопасные части (я имею в виду SGMLReader). - person net_prog; 18.09.2011
comment
Итак, логически - на этот раз у меня было первое исключение (из-за проглатывания), которое завершило мою программу, и это исключение было критическим (не улавливаемым управляемым кодом). Было бы это исключением PageHeap, оно не указывало бы на StringBuilder, что является отвлекающим маневром. Итак, PageHeap не вызывал исключения (хотя я вижу, что куча неверна в соответствии с моим обновлением выше), это означает, что происходит что-то еще или есть проблемы с моими настройками PageHeap ... Мне действительно нужен толчок в правильном направлении . - person net_prog; 18.09.2011
comment
Я бы начал с выяснения, кто звонил в TerminateProcess. Проверьте использование ваших блоков try / catch на предмет возможного покрытия catch (Exception). Ничего страшного, если вы выполняете перехват одеяла, но убедитесь, что вы повторно генерируете исключение. Для неуправляемого кода (если он у вас есть) не используйте catch (...). - person seva titov; 19.09.2011
comment
Очень интересно, взгляните на последний ответ здесь. Это связано с моим делом? - person net_prog; 28.09.2011
comment
Это может быть таким же. Поведение аналогично, но вы не можете сказать, если не знаете, что вызвало проблему в статье, которую вы нашли, и не можете подтвердить, что та же проблема повреждает кучу GC в вашем случае. Сходство стека вызовов в этом случае не имеет значения, потому что это происходит спустя много времени после повреждения. - person seva titov; 28.09.2011
comment
В моем случае PageHeap не помогает (совсем не срабатывает), так же, как AppVerifier, так же, как флаг COMPLUS_HeapVerify. Это повреждение очень странное, учитывая, что у меня нет неуправляемого кода. В то же время последний сбой ясно показывает проблему с кучей с командой !verifyheap (последний хороший объект показан как FreeObject - как это происходит и почему - не знаю). Я уже задавал здесь несколько вопросов, пытаясь понять, как управляемый код может повредить кучу. - person net_prog; 28.09.2011