Domanda

Sto riscontrando un vicolo cieco con uno dei client che utilizza il mio software. Di circa 40 copie del nostro prodotto venduto (Applicazione programmata in .NET 2.0 utilizzando VB.NET 2005), circa 2 non rispondono con 1 core delle CPU dual core bloccato al 100% (il programma utilizza solo 1 core)

L'ipotesi più logica è un loop infinito che causa questo comportamento, ma ci sono migliaia di righe di codice con molti, molti loop. Queste sono tutte le informazioni che ho; ora, come mi consigliate di affrontare il debug di questo problema?

EDIT: Fondamentalmente, il software è responsabile del calcolo della quantità di credito speso utilizzando altri dispositivi, come PC, ecc. È un programma di gestione Cybercafe e fallisce in modo intermittente, ovvero sottrae credito quando fallisce. Fa anche altre cose in background, come verificare se è il momento di creare un backup del database, tra le altre cose.

EDIT: Risolto. Era il problema più improbabile. Il motore di database di Access che ho usato come DBMS è in realtà la parte della mia applicazione che è problematica. Ha difficoltà a lavorare con una riga - SOLO UNA FRIGGIN ROW - in una delle tabelle. Non posso eliminarlo o aggiungere un record relativo a quella riga in qualsiasi altra tabella; Anche MS Access 2007 fa sì che la CPU salga al 100% quando provo a lavorare con quella riga!

Un semplice "Compatto e riparatore" comando risolto tutto. Immagino che invierò quel comando ogni volta che la mia applicazione si avvia. Ciò impedirebbe che ciò accada di nuovo.

Grazie a WinDbg ho trovato il problema. Consiglio a tutti di imparare come usarlo perché è un vero risparmio di tempo.

È stato utile?

Soluzione

Installa windbg (debugger di Windows) sul computer di destinazione. Richiamare il debugger e collegarsi al processo sospetto, eseguire il programma e attendere che si verifichi il problema. Quando si verifica il problema, richiamare il seguente comando nella riga di comando del debugger

! Runaway

Questo mostrerà quali dei tuoi thread stanno consumando la maggior parte del tempo. Quindi ottieni diversi stack di thread da quel thread che sta consumando la maggior parte delle tue risorse della CPU.

Ecco un esempio:

0:015> !runaway

Ora modalità utente   Thread Time    0: 1074 0 giorni 0: 00: 21.637   11: 137c 0 giorni 0: 00: 02.792    4: 12c8 0 giorni 0: 00: 00.530    9: 1374 0 giorni 0: 00: 00.046   15: 13d0 0 giorni 0: 00: 00.000   14: 1204 0 giorni 0: 00: 00.000   13: 154c 0 giorni 0: 00: 00.000   12: 144c 0 giorni 0: 00: 00.000   10: 1378 0 giorni 0: 00: 00.000    8: 1340 0 giorni 0: 00: 00.000    7: 12f0 0 giorni 0: 00: 00.000    6: 12d4 0 giorni 0: 00: 00.000    5: 12d0 0 giorni 0: 00: 00.000    3: 12c4 0 giorni 0: 00: 00.000    2: 12c0 0 giorni 0: 00: 00.000    1: 12b4 0 giorni 0: 00: 00.000

Ora supponiamo che desideriamo uno stack di chiamate per il secondo thread nell'elenco, thread 11, quindi passiamo prima al thread 11. Questo può essere fatto inserendo ~ 11s.

0:015> ~11s

eax = 03fbb270 ebx = ffffffff ecx = 00000002 edx = 00000060 esi = 00000000 edi = 00000000 eip = 77475e74 esp = 0572f60c ebp = 0572f67c iopl = 0 nv up ei pl zr na pe nc cs = 001b ss = 0023 ds = 0023 es = 0023 fs = 003b gs = 0000 efl = 00000246 ntdll KiFastSystemCallRet: 77475e74 c3 ret

Ora ottieni uno stack di chiamate per questo thread eseguendo kp:

0:011> kp
ChildEBP RetAddr  
0572f608 77475620 ntdll!KiFastSystemCallRet
0572f60c 75b09884 ntdll!NtWaitForSingleObject+0xc
0572f67c 75b097f2 kernel32!WaitForSingleObjectEx+0xbe
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Mozilla Firefox 3.1 Beta 1\nspr4.dll - 
0572f690 10019a0b kernel32!WaitForSingleObject+0x12
WARNING: Stack unwind information not available. Following frames may be wrong.
0572f6ac 10015979 nspr4!PR_MD_WAIT_CV+0x8b
0572f6c4 10015763 nspr4!PR_GetPrimordialCPU+0x79
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Mozilla Firefox 3.1 Beta 1\xul.dll - 
0572f6e0 64d44d6a nspr4!PR_Wait+0x33
0572f708 64dbe67e xul!NS_CycleCollectorForget2_P+0x698a
0572f72c 10019b3f xul!gfxWindowsPlatform::FontEnumProc+0xfd4e
0572f734 10015d32 nspr4!PR_MD_UNLOCK+0x1f
0572f738 1001624b nspr4!PR_Unlock+0x22
0572f754 1001838d nspr4!PRP_TryLock+0x4cb
00000000 00000000 nspr4!PR_Now+0x109d

Il comando kp stamperà i parametri. Le variabili locali possono essere stampate con dv.

In alternativa è possibile utilizzare Process Explorer da sysinternals.

Se tutto ciò non è possibile, poiché si tratta di un computer client remoto, installare userdump, che crea un file di dump che può essere inviato all'utente per ulteriori analisi. È possibile creare un file batch per il cliente per richiamare userdump con i parametri corretti. Userdump è uno strumento di Microsoft, che può essere scaricato dalla loro pagina Web.

Altri suggerimenti

Se possibile, ottieni un dump del processo e guarda la traccia dello stack.
Non l'ho mai fatto, ma dovrebbe funzionare con VS / WinDbg e SOS (Son of Strike). Ecco un post sul blog a riguardo.

Se si tratta di un ciclo infinito, prova a collegare un debugger e a colpire l'interruzione. WinDbg è l'ideale per questo.

La tecnica funziona anche nel caso in cui il ciclo stia ripetendo troppe volte ma alla fine continui con il resto del codice. È possibile passare un paio di minuti a ripetere la procedura per ottenere un buon campione.

Questa tecnica mi ha salvato diverse volte e funziona bene anche per applicazioni sospese :)

Beh, dovrai capire dove sono i loop. Cosa sta facendo il tuo cliente con il software in quel momento? Che cosa fa il software in primo luogo?

Potresti prendere in considerazione l'aggiunta di molte registrazioni al tuo codice e dare una copia al client con tutte le registrazioni abilitate, aiutandoti a rintracciare dove stanno avendo problemi.

Usa un logger come log4net che puoi presentare alla tua base di codice esistente con < a href = "http://www.postsharp.org/" rel = "nofollow noreferrer"> postsharp . Registra tutte le voci e le uscite del metodo, quindi dovresti trovare il metodo difettoso. Quindi puoi migliorare la tua registrazione se è ancora richiesta.

Sembra che funzioni anche per vb.net, anche se non ho esperienza lì. Forse questo articolo aiuta un po '.

Dovrai intervistare quei clienti molto attentamente. Non è sempre facile, ma è la tua unica possibilità di restringere il problema.

Quindi aggiungi attentamente Traccia e non dimenticare di scaricare in punti strategici (o impostare AutoFlush).

Ma potrebbe essere un sottile problema di temporizzazione che si risolve a causa del ritardo aggiunto della traccia ...

Potrebbe essersi verificato un problema con le CPU single-core e multi-core che si comportano diversamente, ad esempio quando un thread in background tenta di aggiornare l'interfaccia utente.

(p single core)

In tal caso, è necessario verificare se la CPU al 100% si verifica solo con un tipo speciale di CPU e se l'utilizzo di SetProcessAffinity risolve il problema. In tal caso, sai dove cercare nel tuo codice.

Potrebbe essere un problema di threading? "fallisce in modo intermittente" fa io ci penso. Il programma riceve segnali / messaggi dall'esterno, come remoting / DCOM / socket? È progresso informazioni relative a tali messaggi presentati nell'utente Interfaccia?

Una volta ho rilevato un problema di threading perché uso sempre a molti ASSERTI. All'inizio c'era un assegno di sanità mentale ASSERT di un messaggio ricevuto tramite XML-RPC come:

"<?xml " 

e ASSERT ha rilevato una sovrascrittura della memoria del messaggio. Di l'ispezione risultò essere dovuta a un blocco mancante in a sezione critica. Questo rilevamento è stato possibile solo perché il problema è stato colto così presto dall'Assert (e da esso è accaduto abbastanza spesso per essere rilevato).

Questo non è un consiglio molto specifico o diretto, ma il mio suggerimento quindi è quello di aggiungere ASSERTI in luoghi che potrebbero essere interessato un problema di threading.

Nota che sparare ASSERT non implica necessariamente l'interruzione il programma o lanciare finestre di messaggio. ASSERT possono essere reindirizzato invece a un file di registro, incluso lo stack completo traccia al momento dell'attivazione di ASSERT.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top