Исключения, возникающие (ошибки обнаружены) после завершения программы - PullRequest
5 голосов
/ 08 октября 2008

У меня есть приложение, которое, похоже, генерирует исключения только после закрытия программы. И это очень противоречиво. (Мы все знаем, как забавны противоречивые ошибки ...)

Я предполагаю, что во время процесса очистки произошла ошибка. Но эти ошибки чтения / записи памяти, похоже, указывают на что-то неправильное в моем «небезопасном» использовании кода (указатели?).

Что меня интересует, так это лучший способ отладки этих ситуаций?
Как вы отлаживаете программу, которая уже закрылась?
Я ищу отправную точку для решения более крупной проблемы.

Кажется, что эти ошибки проявляются несколькими способами (некоторые во время выполнения, некоторые отладки):

1: .NET-BroadcastEventWindow.2.0.0.0.378734a.0:  Application.exe - Application Error<BR>
The instruction at "0x03b4eddb" referenced memory at "0x00000004". The memory could not be "written".

2:  Application.vshost.exe - Application Error<br>
The instruction at "0x0450eddb" referenced memory at "0x00000004". The memory could not be "written".

3:  Application.vshost.exe - Application Error<br>
The instruction at "0x7c911669" referenced memory at "0x00000000". The memory could not be "read".

4:  Application.vshost.exe - Application Error<br>
The instruction at "0x7c910ed4" referenced memory at "0xfffffff8". The memory could not be "read".

Ответы [ 6 ]

6 голосов
/ 09 августа 2010

У меня возникла эта проблема при использовании компонента COM AcrobarReader. Время от времени после выхода из приложения у меня появлялось «Application.vshost.exe - Ошибка приложения», «память не читалась». GC.Collect () и WaitForPendingFinalizers () не помогли.

Мой гугл-фу привел меня на эту страницу: http://support.microsoft.com/kb/826220. Я изменил метод 3 для моего случая.

Используя Process Explorer, я обнаружил, что AcroPDF.dll не выпускается до последней строки в функции Main. Итак, вот и вызовы API.

DLLImports (DLLImport находится в пространстве имен System.Runtime.InteropServices):

<DllImport("kernel32.dll", EntryPoint:="GetModuleHandle", _
       SetLastError:=True, CharSet:=CharSet.Auto, _
       CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function GetModuleHandle(ByVal sLibName As String) As IntPtr
End Function

<DllImport("kernel32.dll", EntryPoint:="FreeLibrary", _
    SetLastError:=True, CallingConvention:=CallingConvention.StdCall)> _
Public Overloads Shared Function FreeLibrary(ByVal hMod As IntPtr) As Integer
End Function

А затем перед выходом из приложения:

Dim hOwcHandle As IntPtr = GetModuleHandle("AcroPDF.dll")
If Not hOwcHandle.Equals(IntPtr.Zero) Then
    FreeLibrary(hOwcHandle)
    Debug.WriteLine("AcroPDF.dll freed")
End If

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

4 голосов
/ 08 октября 2008

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

1 голос
/ 08 октября 2008

Более причудливое слово для "непоследовательного" - "недетерминированный". И что происходит недетерминированно в среде .NET? Уничтожение объекта.

Когда это случилось со мной, виновник был в классе, который я написал, чтобы обернуть небезопасные вызовы во внешний API. Я поместил код очистки в деструктор класса, ожидая, что код будет вызван, когда объект выйдет из области видимости. Но это не то, как уничтожение объектов работает в .NET. Когда объект выходит из области видимости, он помещается в очередь финализатора, и его деструктор не вызывается, пока финализатор не дойдет до него. Это не может сделать это, пока программа не завершится. Если это произойдет, результат будет очень похож на то, что вы здесь описываете.

Как только я заставил свой класс реализовать IDisposable и явно вызвал Dispose() для объекта, когда я закончил, проблема исчезла. (Еще одним преимуществом реализации IDisposable является то, что вы можете создать экземпляр своего объекта в начале блока using и быть уверенным, что Dispose () получит, когда код покинет блок.)

1 голос
/ 08 октября 2008

Я недавно видел много ошибок, подобных этой. Мои проблемы были связаны с тем, как CRT (C Runtime), взаимодействующий с .NET runtime, очищает процесс закрытия. Мое приложение усложняется тем, что это C ++, но позволяет загружать надстройки COM, некоторые из которых написаны на C #.

Для отладки, я думаю, вам нужно использовать встроенную отладку. Visual Studio (для отладки в смешанном режиме) или WinDbg. Посмотрите, как использовать общедоступный сервер символов Microsoft для загрузки PDB для компонентов Windows - вам понадобится этих символов.

Многие из наших проблем были связаны с (ужасной) поддержкой COM-клиентов .NET. Я говорю ужасно, потому что это неправильно подсчитывает ссылки (без большой работы на стороне разработчика). На COM-объекты не было обращено отсчет до нуля, пока не была выполнена сборка мусора. Это часто вызывает странные проблемы с синхронизацией во время выключения - COM-объекты очищаются задолго до того, как они должны были быть.

0 голосов
/ 14 мая 2010

Ошибка перестала появляться после использования предложенного кода:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 
0 голосов
/ 24 ноября 2008

попробуйте, чтобы ошибка произошла под управлением программы

   //set as many statics as you can to null;
   GC.Collect();
   GC.WaitForPendingFinalizers();
} //exit main
...