2012-04-05 9 views
6

Sto costruendo un'applicazione delphi che esegue la simulazione scientifica. Sta crescendo in complessità & ora consiste di molte unità e forme.Delphi: come trovare e correggere un errore EOutOfMemory?

sto iniziando a ottenere gli errori EOutOFMemory ogni volta che corro. Sembra che accada durante o subito dopo che utilizzo una matrice di varianti temporaneamente all'interno di una funzione. A rischio di fare una domanda davvero stupida, la "matrice di varianti" richiede problemi? (Potrei convertire tutto in stringa, ma l'array di varianti in linea di principio consente di risparmiare un sacco di cose di disturbo).

l'incriminato uso array potrebbe essere:

Function TProject.GetCurrentProjParamsAsArray(LProjectName, LProjectType : ShortString): ArrayOfVariant; 
Var 
    ArrayIndex : Word; 
begin 
    SetLength (Result,54); 
    ArrayIndex := 0; 
    Result [ArrayIndex] := LProjectName;  Inc(ArrayIndex); 
    Result [ArrayIndex] := LProjectType;  Inc(ArrayIndex);     // this structure makes it easier to add extra fields in the DB than hard coding the array index!! 
    Result [ArrayIndex] := FileTool.DateTimeForFileNames ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteName   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. PostCode   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. MetFileNamePath  ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteLat    ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteLong   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. SiteAlt    ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. TZoneIndex   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. TZoneHours   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. TZoneMeridian  ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. Albedo    ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. ArrayTilt   ; Inc(ArrayIndex); 
    Result [ArrayIndex] := SiteAndMet. ArrayAzimuth  ; Inc(ArrayIndex); 

in Task Manager - l'utilizzo della memoria di picco è 42MB, VM è 31M e sto ricevendo ~ 90.000 errori di pagina al run. (su una macchina xp con RAM da 3 GB)

Qualcuno ha suggerimenti generali sul monitoraggio dell'utilizzo della memoria da parte dei diversi componenti all'interno della mia applicazione? o per rintracciare la causa di questo errore?

Recentemente sono passato dall'archiviazione dei dati del progetto principale come CSV all'utilizzo dei DB ADO, Allo stesso tempo, ho anche iniziato a utilizzare il tipo di dati Variant piuttosto che a convertire la stringa betweem e singola/doppia tutto il tempo.

Ho seguito vari suggerimenti per il risparmio di memoria che posso trovare, in cui pratico ho rimosso Application.CreateForm (TProject, Project); dichiarazioni dal .dpr e creandole dinamicamente. (eccetto dove i moduli vengono usati la maggior parte del tempo comunque). Generaly Io uso più piccolo tipo di dati pratico (byte, ShortString, ecc) e ridurre al minimo l'uso di variabili 'pubblici' & funzioni

qualche consiglio molto graditi, Brian

+0

Si prevede di ottenere errori di pagina. Non preoccuparti di questo. Un 'array di Variant' non suona male. Dopo tutto hai solo 54 elementi nella matrice. 42 MB è banale. Quasi impossibile dire cosa sta succedendo dato questa informazione. –

+0

Come viene definito 'ArrayOfVariant'? stai memorizzando oggetti nell'array o solo tipi semplici? – RRUZ

+0

ArrayOfVariant è definito in un'unità di servizio separata (poiché non è possibile passare "Array Of ...." tra le funzioni, ad esempio ArrayOfVariant = Array of Variant; contiene solo valori Double e String. – SolarBrian

risposta

2

dubito che il codice si sta mostrando, è la fonte del problema. È probabilmente un luogo in cui si verifica un sintomo.

Se si sospetta che si abbia effettivamente qualche corruzione di basso livello di base, si potrebbe voler provare a attivare la modalità di debug completo di FastMM. Ad esempio, problemi come quello che stai incontrando potrebbero essere causati da un danneggiamento generale dell'heap della memoria invece di esaurire la memoria.

Se non si ha il danneggiamento dell'heap, ma si ha invece un vero problema di memoria esaurita, per trovarlo e risolverlo di solito è necessario uno strumento adeguato, chiamato profiler, come AQTime. Forse il tuo codice di allocazione è sbagliato in un modo che puoi capire se esegui semplicemente il debug del tuo codice, e trovi che da qualche parte stai cercando di afferrare una quantità irragionevole di memoria, in una, o una serie di chiamate ad una funzione di allocazione della memoria.

Tuttavia, senza un profiler, come la suite di qualità nexus o AQTime, o un altro strumento simile, sarete per lo più ciechi. L'applicazione sta semplicemente fallendo e il codice di gestione dell'heap sta segnalando che ha esaurito la memoria. È possibile che tu stia facendo qualcosa da qualche parte che sta corrompendo il tuo heap. È possibile che stiate allocando troppa memoria per il vostro processo a 32 bit. È possibile che il tuo computer non abbia abbastanza memoria reale o virtuale, o che tu stia allocando un'enorme struttura dati che non hai realizzato non è pratico, all'interno della tua applicazione.

+0

hmm AQTime proverà anche questo, grazie! – SolarBrian

+0

AQTime è abbastanza costoso, in passato il processo mi ha aiutato molto. C'è anche http://www.prodelphi.de/ – LaBracca

+0

Prova invece la suite di qualità nexus o, per un'idea gratuita, usa FastMM in modalità di debug completo e usa i dump dell'heap per determinare COSA sta usando la tua memoria. –

10

EOutOfMemory si verifica quando il gestore della memoria non riesce a trovare un blocco contigious della memoria per una determinata richiesta di allocazione. Quindi sei 1) allocare più memoria di quanto ti aspetti, 2) la perdita di memoria che hai allocato correttamente, o 3) frammentare (non necessariamente perdendo) la memoria in modo che il gestore della memoria debba continuare ad allocare sempre più memoria nel tempo.

Quando si verifica l'eccezione, guarda lo stack di chiamate. Ciò ti porterà al codice che non riesce ad allocare memoria. Per ottenere lo stack di chiamate, eseguire l'applicazione nel debugger, o utilizzare un quadro di registrazione un'eccezione come MadExcept, EurekaLog, JCLExcept, ecc

+2

La frammentazione è una spiegazione plausibile.Ma sapere quale allocazione fallisce raramente aiuta a spiegare come la memoria è diventata frammentata. –

+0

Di solito, ma a volte può, se il codice che si blocca è il lo stesso codice frammentato. –

+0

Ah, i framework di registrazione delle eccezioni sembrano molto utili, grazie Lo proverò! – SolarBrian

2

Avete installato la versione completa del gestore di memoria FastMem? Può aiutarti a rintracciare gli errori nella gestione della memoria. Vedi se stai perdendo qualcosa.

Se non si dispone di una perdita, si ha un problema di frammentazione piuttosto estremo, sarà necessario gestirlo mantenendo un gruppo di oggetti anziché allocarli/deallocarli.

+0

FastMM - proverà grazie! – SolarBrian

2

Per trovare una causa delle eccezioni OutOfMemory è necessario esaminare la creazione di tutti gli oggetti e non solo il punto in cui viene sollevata l'eccezione.

Uno strumento di terza parte come EurekaLog può mostrare tutti gli oggetti istanziati sull'applicazione e non correttamente disposti. Puoi provare a correggerli usando try finally blocks con la procedura FreeAndNil.

+0

mmm, recentemente ho aggiunto un sacco di Create/Free per ridurre l'overhead della memoria dai moduli usati raramente, quindi questo potrebbe essere il problema. Grazie! – SolarBrian

2

Suona come perdite di memoria.

Aggiungo sempre un

{$IFDEF DEBUG} 
    ReportMemoryLeaksOnShutdown := DebugHook <> 0; 
    {$ENDIF} 

al file di origine di progetto per la mia build di debug.

Ciò fornisce una buona indicazione di quanto bene ho creato il programma.

+0

+1 @andy_k ma dove lo aggiungi? – Mawg

Problemi correlati