Domanda

Ho un'applicazione che sembra generare eccezioni solo dopo la chiusura del programma. Ed è molto incoerente. (Sappiamo tutti quanto sono divertenti i bachi inconsistenti ...)

Suppongo che si sia verificato un errore durante il processo di pulizia. Ma questi errori di lettura / scrittura della memoria sembrano indicare qualcosa di sbagliato nel mio "non sicuro" utilizzo del codice (puntatori?).

Quello che mi interessa è qual è il metodo migliore per eseguire il debug di queste situazioni?
Come si esegue il debug di un programma che è già stato chiuso?
Sto cercando un punto di partenza per risolvere un problema più grande.

Questi errori sembrano presentarsi in diversi modi (alcuni runtime, altri debug):

1: .NET-BroadcastEventWindow.2.0.0.0.378734a.0:  Application.exe - Application Error
The instruction at "0x03b4eddb" referenced memory at "0x00000004". The memory could not be "written". 2: Application.vshost.exe - Application Error
The instruction at "0x0450eddb" referenced memory at "0x00000004". The memory could not be "written". 3: Application.vshost.exe - Application Error
The instruction at "0x7c911669" referenced memory at "0x00000000". The memory could not be "read". 4: Application.vshost.exe - Application Error
The instruction at "0x7c910ed4" referenced memory at "0xfffffff8". The memory could not be "read".
È stato utile?

Soluzione

Se l'app è multi-thread, potresti ricevere errori dai thread di lavoro che non si terminano correttamente e tentano di accedere agli oggetti eliminati.

Altri suggerimenti

Ho riscontrato questo problema utilizzando il componente COM AcrobarReader. Ogni tanto dopo l'uscita dell'applicazione avevo " Application.vshost.exe - Errore applicazione " "impossibile leggere la memoria". GC.Collect () e WaitForPendingFinalizers () non ha aiutato.

Il mio google-fu mi porta a questa pagina: http://support.microsoft.com/kb / 826220 . Ho modificato il metodo 3 per il mio caso.

Utilizzando Process Explorer, ho scoperto che AcroPDF.dll non è stato rilasciato prima dell'ultima riga della funzione Main. Quindi, ecco che arrivano le chiamate API.

DLLImports (DLLImport si trova nello spazio dei nomi 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

E poi prima dell'uscita dall'applicazione:

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

Questa procedura può essere modificata per qualsiasi altra dll mal condotta. Spero solo che non presenti nuovi bug.

Ho visto molti errori proprio così recentemente. I miei problemi sono stati ricondotti al modo in cui il CRT (C Runtime) che interagisce con il runtime .NET ripulisce un processo di chiusura. La mia applicazione è complicata dal fatto che è C ++, ma consente di caricare componenti aggiuntivi COM, alcuni dei quali sono scritti in C #.

Per eseguire il debug, penso che dovrai usare il debug nativo. Visual Studio (impostato sul debug in modalità mista) o WinDbg. Cerca come utilizzare il server dei simboli pubblici di Microsoft per scaricare i PDB per i componenti di Windows: ne bisogno quei simboli.

Molti dei nostri problemi riguardavano il (terribile) supporto client COM di .NET. Dico terribile dal momento che non fa riferimento correttamente al conteggio (senza molto lavoro da parte dello sviluppatore). Gli oggetti COM non venivano referenziati fino a zero fino a quando non veniva eseguita la garbage collection. Questo spesso imposta problemi di temporizzazione dispari durante l'arresto - gli oggetti COM vengono ripuliti molto tempo dopo che avrebbero dovuto essere.

Una parola più elaborata per "incoerente" è "non deterministico". E cosa succede in modo non deterministico nell'ambiente .NET? Distruzione di oggetti.

Quando questo è successo a me, il colpevole era nella classe che ho scritto per avvolgere le chiamate non sicure verso un'API esterna. Ho inserito il codice di pulizia nel distruttore della classe, aspettandomi che il codice venisse chiamato quando l'oggetto non rientrava nell'ambito. Ma non è così che funziona la distruzione degli oggetti in .NET, quando un oggetto esce dall'ambito di applicazione, viene messo nella coda del finalizzatore e il suo distruttore non viene chiamato fino a quando il finalizzatore non riesce ad aggirarlo. Non può farlo fino al termine del programma. In questo caso, il risultato sarà molto simile a quello che stai descrivendo qui.

Una volta che la mia classe ha implementato IDisposable , e ho esplicitamente chiamato Dispose () sull'oggetto quando ho finito con esso, il problema è scomparso. (Un altro vantaggio dell'implementazione di IDisposable è che puoi istanziare il tuo oggetto all'inizio di un blocco using ed essere sicuro che Dispose () otterrà quando il codice lascia il blocco.)

prova questo per forzare il verificarsi del bug sotto il controllo del programma

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

L'errore ha smesso di apparire dopo aver usato il codice suggerito:

GC.Collect(); 
GC.WaitForPendingFinalizers(); 
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top