2012-04-11 14 views
8

Non riesco a capirlo. Il mio programma viene compilato ed eseguito correttamente, ma durante il debug solo si apre una finestra di messaggio che dice "Operazione di puntatore non valida" quando si chiude il programma. Ho accuratamente controllato tutti gli eventi FormCloseQuery e FormDestory per qualsiasi sintassi o errore logico. Non ho trovato nessuno e si eseguono come previsto senza alcun errore.Operazione di puntamento non valida - Delphi XE

enter image description here

Quando faccio dire al compilatore di rompere in errore puntatore non valido operazione, non fa nulla, ma riaggancia il programma. A quel punto, ho dovuto terminare o uccidere il processo.

Come si calcola questo?

Grazie in anticipo,

+6

Abilita il debug delle DCU e passa attraverso l'arresto finché non trovi ciò che attiva questo errore. Stai correndo con FastMM in modalità Full Debug? –

+0

@DavidHeffernan, :) Ricordo che abbiamo avuto una conversazione su FastMM. Sfortunatamente, non ho usato FastMM da quando ho eseguito il test sul retro. Attiverò la DCU e vedrò cosa succede. – ThN

+0

@DavidHeffernan, dopo l'interruzione con dcu abilitato, il debugger si è fermato nel file System.pas. Un po 'di confusione, ma penso sia perché è una delle ragioni di Mason Wheeler. Credo che ora devo rimandare FastMM. – ThN

risposta

25

eccezione Un puntatore non valido viene generato dal gestore della memoria quando si tenta di liberare memoria non valida. Ci sono tre modi in cui ciò può accadere.

Il più comune è perché stai provando a liberare un oggetto che hai già liberato. Se si attiva la modalità FullDebug di FastMM, questa verrà rilevata e indirizzata direttamente al problema. (Ma assicurati di creare un map file in modo che abbia le informazioni necessarie per creare utili tracce dello stack.)

Il secondo modo è se stai provando a liberare memoria allocata in un punto diverso dal gestore della memoria . L'ho visto alcune volte quando si passava una stringa da da un file EXE di Delphi a una DLL di Delphi che non utilizzava la funzione di gestione della memoria condivisa.

E il terzo modo implica fare confusione con i puntatori direttamente e probabilmente non si applica a voi. Se si prova a FreeMem o Dispose un puntatore non valido che non fa riferimento a un blocco effettivo di memoria assegnato da FastMM, si otterrà questo errore.

È molto probabilmente il primo. Usa FullDebugMode e troverai facilmente la fonte del problema.

+0

hai assolutamente ragione. Il tuo primo motivo è il motivo per cui il mio programma sta sollevando questa notifica di eccezione. Tuttavia, sta rilanciando perché l'evento di distruzione del mio TForm è chiamato più di una volta. Che non capisco perché. – ThN

+0

Se dovessi fare un'ipotesi, direi perché il tuo modulo è stato creato con un proprietario (come ad esempio Application, hai usato 'Application.CreateForm' per costruirlo?) E poi da qualche altra parte stai cercando di liberarlo manualmente. Dai un'occhiata alle tracce dello stack per le due volte che viene liberato; ti daranno un'idea di cosa sta succedendo. E mantieni presente il [Single Ownership Principle] (http://tech.turbu-rpg.com/106/delphi-memory-management-made-simple): i tuoi moduli possono essere di proprietà di Application o del tuo codice, ma non da entrambi. –

0

Sono stato colto da questo tipo di "errore indicato" durante il debug di Delphi.

Verificare se ci sono variabili controllate con "Consenti chiamate funzione" abilitate o orologi che tentano di mostrare altre variabili nella stessa unità (o globale) che potrebbero non essere inizializzate. Quando si ferma su un punto di interruzione, ciò può far sì che il debugger di Delphi tenti di visualizzare il valore tramite una chiamata di funzione che accede a un puntatore o variabile non inizializzata. La variabile effettiva che causa il mio AV non è nemmeno nella tua lista di controllo.

+3

EAccessViolation è diverso da EInvalidPointer. * Accedendo a * un puntatore non valido restituisce il primo; solo * liberare * fornisce quest'ultimo. –

9

Le operazioni di puntatore non valide si verificano quando si comunica al responsabile della memoria Delphi di rilasciare memoria che non gli appartiene. Ci sono tre modi che potrebbero accadere:

  • Liberare un puntatore o un oggetto che è già stato liberato.
  • Utilizzo di FreeMem per liberare qualcosa che è stato allocato da qualche altro gestore di memoria (come GlobalAlloc o CoTaskMemAlloc).
  • Liberare un puntatore non inizializzato. (Questo è diverso dal liberare un puntatore nullo, che è completamente sicuro.)

Da qualche parte nel tuo programma, stai facendo una di quelle cose.Il debugger ha rilevato l'eccezione generata dal gestore della memoria, quindi esegui il debug. Dalla traccia dello stack, dovresti essere in grado di vedere quale variabile stai provando a liberare. Controlla il resto del tuo programma per altri modi in cui viene utilizzata questa variabile.

Strumenti come MadExcept e Eureka Log possono aiutarti a trovare errori double-free. Possono tenere traccia di dove il puntatore in questione è stato assegnato e dove è stato liberato la prima volta, e questo a volte è abbastanza informazioni per capire il tuo errore e smettere di liberare le cose più volte.

+0

Viene anche generato se si tenta di liberare l'indirizzo di un oggetto dichiarato localmente? – Wolf

+0

Sì, @ Wolf. Questo è coperto dal secondo punto elenco. In tal caso, tenteresti di liberare memoria allocata nello stack. –

+0

Grazie. Questo "allocato" o "gestore della memoria" sembra strano quando si parla di variabili automatiche. Forse questo dovrebbe essere aggiunto anche (in un modo più esplicito)? – Wolf

1

Una quarta ragione per cui può verificarsi un'operazione di puntatore non valida. Ho avuto due puntatori che in cui matrice [0..1000] di puntatore reale e un terzo che era un array [1..200] di reale. Tutti e 3 i puntatori inizializzati con per i: = da 0 a 1000 do iniziano ptr1^[i]: = 0; ptr2^[i]: = 0; ptr3^[i]: = 0; fine; Mentre questa scarsa programmazione non ha disturbato Pascal in Delphi, una chiamata a Dispose qualsiasi dei 3 puntatori ha provocato un'operazione di puntatore non valida. La correzione era semplicemente per inizializzare correttamente il terzo puntatore.

Problemi correlati