2012-04-05 15 views
6

Estoy construyendo una aplicación delphi que hace simulación científica. Está creciendo en complejidad & ahora consta de muchas unidades y formularios.Delphi: ¿Cómo encontrar y corregir un error de EOutOfMemory?

Empiezo a recibir errores de EOutOFMemory cada vez que ejecuto. Parece suceder durante o justo después de que utilizo una Matriz de variante temporalmente dentro de las funciones. A riesgo de hacer una pregunta realmente tonta, ¿hay "variedad de variantes" que piden problemas? (Podría convertir todo a cadena, pero la matriz de variante, en principio, ahorra muchas cosas falsas).

el infractor gama uso podría ser:

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); 

En administrador de tareas - el uso de memoria máximo es de 42 MB, VM es 31M y yo estoy poniendo ~ 90.000 errores de páginas por serie. (en una máquina xp con 3 GB de ram)

¿Alguien tiene alguna sugerencia general sobre la supervisión del uso de la memoria por los diferentes componentes de mi aplicación? o al rastrear la causa de este error?

Recientemente he pasado de almacenar los datos principales del proyecto como CSV a utilizar ADO DBs, Al mismo tiempo, también he comenzado a usar el tipo de datos Variant en lugar de convertir betweem string y single/double todo el tiempo.

he seguido varios consejos para el ahorro de memoria que puedo encontrar, en la práctica eliminé Application.CreateForm (TProject, Project); declaraciones del .dpr y crearlas dinámicamente. (excepto donde los formularios se usan la mayor parte del tiempo de todos modos). Generaly utilizo más pequeño tipo de datos prácticos (byte, ShortString, etc) y reducir al mínimo el uso de variables 'públicas' & funciones

algún consejo muy bienvenida, Brian

+0

Espera obtener errores de página. No te preocupes por eso Un 'array of Variant' no suena tan mal. Después de todo, solo tienes 54 elementos en la matriz. 42 MB es trivial. Casi imposible decir qué está pasando con esta información. –

+0

¿Cómo se define 'ArrayOfVariant'? ¿Estás almacenando objetos en la matriz o solo tipos simples? – RRUZ

+0

ArrayOfVariant se define en una unidad de utilidad separada (ya que no puede pasar 'Array Of ....' entre funciones, es decir, ArrayOfVariant = Array of Variant; Contiene solo valores dobles y de cadena. – SolarBrian

Respuesta

2

Dudo que el código que está mostrando sea la fuente del problema. Es probable que sea un lugar donde ocurre un síntoma.

Si sospecha que tiene, de hecho, algunos daños básicos de nivel bajo, puede intentar activar el modo de depuración completo de FastMM. Por ejemplo, problemas como el que está encontrando podrían deberse a daños en el montón de memoria general en lugar de quedarse sin memoria.

Si no tiene daños en el montón, pero en cambio tiene un verdadero problema de memoria insuficiente, entonces encontrarlo y resolverlo generalmente requiere una herramienta adecuada, llamada generador de perfiles, como AQTime. Tal vez su código de asignación es incorrecto de una manera que puede entender si simplemente depura su código, y descubre que en algún lugar está tratando de obtener una cantidad irracional de memoria, ya sea en una, o una serie de llamadas a alguna función de asignación de memoria.

Sin embargo, sin un generador de perfiles, como Nexus Quality Suite o AQ Time, u otra herramienta similar, será casi ciego. Su aplicación simplemente está fallando y el código de administración del montón informa que se ha quedado sin memoria. Es posible que estés haciendo algo en alguna parte que esté corrompiendo tu montón. Es posible que realmente esté asignando demasiada memoria para su proceso de 32 bits. Es posible que su computadora no tenga suficiente memoria real o virtual, o que esté asignando una gran estructura de datos que usted no se haya dado cuenta de que no es práctica, dentro de su aplicación.

+0

hmm AQTime lo intentará también, ¡Gracias! – SolarBrian

+0

AQ Time es bastante expesivo, en el pasado la prueba me ayudó mucho. También hay http://www.prodelphi.de/ – LaBracca

+0

Pruebe la suite de calidad nexus en su lugar, o para una idea libre, use FastMM en modo de depuración completa, y use volcados de almacenamiento dinámico para determinar QUÉ está usando su memoria. –

10

EOutOfMemory se produce cuando el administrador de memoria no puede encontrar un bloque contigious de la memoria para una solicitud de asignación dada. Entonces, o bien está 1) asignando más memoria de la que espera, 2) filtrando memoria que ha asignado correctamente, o 3) memoria fragmentada (no necesariamente con fuga) para que el administrador de memoria tenga que seguir asignando más y más memoria a lo largo del tiempo.

Cuando se produce la excepción, observe la pila de llamadas. Eso lo llevará al código que no asigna memoria. Para obtener la pila de llamadas, ejecute su aplicación en el depurador o use un marco de registro de excepciones como MadExcept, EurekaLog, JCLExcept, etc.

+2

La fragmentación es una explicación plausible. Pero saber qué asignación falla rara vez ayuda a explicar cómo se fragmentó la memoria. –

+0

Por lo general, pero a veces puede, si el código que está fallando es el mismo código que se está fragmentando. –

+0

Ah, los marcos de registro de excepciones suenan muy útiles, gracias " lo intentaré! – SolarBrian

2

¿Ha instalado la versión completa del administrador de memoria FastMem? Puede ayudarlo a localizar errores en el manejo de la memoria. Vea si está filtrando algo.

Si no tiene una fuga, tiene un problema de fragmentación bastante extremo, tendrá que lidiar con ello manteniendo un conjunto de objetos en lugar de seguir asignándolos/desasociándolos.

+0

FastMM - ¡lo intentaré gracias! – SolarBrian

2

Para encontrar una causa de las excepciones de OutOfMemory, debe buscar en todos los objetos creados y no solo en donde se produce la excepción.

Una herramienta de tercera parte como EurekaLog puede mostrarle todos los objetos instanciados en la aplicación y no eliminados correctamente. Puede intentar corregirlos utilizando bloques try finally con el procedimiento FreeAndNil.

+0

mmm, Recientemente he agregado una gran cantidad de crear/liberar para reducir la sobrecarga de memoria a partir de formularios poco utilizados, por lo que este podría ser el problema. ¡Gracias! – SolarBrian

2

Suena como pérdidas de memoria.

siempre agrego un

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

al archivo fuente del proyecto para mi versiones de depuración.

Esto da una buena indicación de lo bien que he construido el programa.

+0

+1 @andy_k pero, ¿dónde lo agregas? – Mawg

Cuestiones relacionadas