2009-07-09 11 views
5

Tuve este desagradable error que desapareció en el pasado, pero ahora después de bastante tiempo regresó.FastMM4 dice "El encabezado del bloque se ha dañado"

Tengo dos objetos TSam (derivados de TPersistent) creados y cargados en un objeto TAsmJob (derivado de TObjectList).

En tiempo de ejecución, un formulario crea un TStringGrid y luego el AsmJob que crea esos dos objetos SAM (y carga algunos datos del disco en cada uno de ellos). AsmJob también se asigna a la grilla. Cuando se destruye el formulario, The Grid se encarga de AsmJob liberándolo, lo que libera los objetos TSam. Aquí está el problema: el primer objeto se libera sin problemas, pero el segundo muere cuando se llama su método heredado (en Destroy destructor).

Utilizo FreeAndNil en todo el programa para liberar los objetos. Los objetos TSam no son NILOS !!!!! Entonces, este es el primer intento de liberar los objetos. Incluso los datos dentro de los objetos son consistentes.

La columna vertebral del programa tiene el siguiente aspecto:

**Create:** 

Form -> StringGrid 
    -> AsmJob -> Sam1, Sam2 
StringGrid.AsmJob:= AsmJob; 


**Free:** 

Form -> StringGrid -> AsmJob -> Sam1, Sam2 

Realmente no entiendo donde intento hacer doble libre o sobrescribir el objeto después de que ha sido puesto en libertad.


edición:

Algunos de los errores que tengo:

  • FastMM ha detectado un error durante una operación de exploración bloque libre. FastMM detectó que un bloque ha sido modificado después de ser liberado.

  • FastMM ha detectado un error durante una operación de exploración de bloque gratuita . El encabezado del bloque se ha dañado.

Detalle:

The current thread ID is 0x19C, and the stack trace (return addresses) leading to this error is: 
402E77 [System][@FreeMem] 
4068DC [System][@DynArrayClear] 
405E2D [System][@FinalizeArray] 
405D31 [System][@FinalizeRecord] 
40432F [System][TObject.CleanupInstance] 
404272 [System][TObject.FreeInstance] 
404641 [System][@ClassDestroy] 
4D313E [UnitSam.pas][TSam.Destroy][297] 
4042BF [System][TObject.Free] 
4149ED [SysUtils][FreeAndNil] 
4D9C0A [UnitAsmJob.pas][UnitAsmJob][TAsmJob.Destroy][180] 

tengo todas las opciones "depuración" habilitadas en el IDE, incluyendo el "rango de control". Además, el FastMM4 está configurado en modo de depuración súper agresivo. Sin FastMM o fuera del depurador, el programa funciona perfectamente, pero aún así sé que no significa que el error ya no esté allí. En realidad funcionó (probablemente) durante más de un año, hasta que instalé FastMM.


edición:

Gracias a todo el mundo. No, estoy sintiendo que me estoy moviendo un poco en la buena dirección.

La estructura del programa es más complicada Ofrecí solo la columna vertebral para mantener la publicación original pequeña. Pero qué diablos, ya se hizo más grande :) Entonces, esos objetos TSam se usan para cargar datos del disco. Un archivo en cada objeto. También están haciendo algo de procesamiento y validación de datos. Para cada uno de estos TSam también tengo un objeto gráfico que muestra en la pantalla (gráficamente) los datos contenidos en los objetos TSam. Cada línea en el TStringGrid también muestra los datos en TSam, pero textualmente.

Una pregunta que tengo: si rompo el programa en trozos más pequeños para descubrir dónde está el error, ¿seguirá apareciendo el error? ¿O es posible aparecer solo en esta configuración particular?


respuesta a "¿cómo el AsmJob se asignan a TStringGrid para que el TStringGrid destruye la AsmJob, nos muestras?"

MyGrid = TStringGrid 
    public 
    AsmJob: TAsmJob; 
    end; 

continuación, en algún lugar del TForm.Create (la forma que tiene el Grid), yo

MyGrid.AsmJob=AsmJob; 

y en el destructor de la MyGrid yo:

begin 
    FreeAndNil(AsmJob); 
    inherited 
end; 

Respuesta

12

Este error significa que su código corrompió las estructuras del administrador de memoria interna. Su pila de llamadas representa un punto, cuando MM detectó esto. Esta no es una ruta de error ni nada relacionado con ella. El error real ocurre ANTES de este momento. Puede o no estar relacionado con las clases mencionadas.

You should try to use "Range check errors" option (don't forget to make Build, not Compile) and FastMM in full debug mode (with CheckHeapForCorruption, CatchUseOfFreedInterfaces и DetectMMOperationsAfterUninstall options enabled).

También puede activar la variable global FullDebugModeScanMemoryPoolBeforeEveryOperation, para obtener un error casi inmediatamente después de que ocurra el problema, pero esta opción ralentiza su ejecución MUCHO.

Probablemente la mejor opción es llamar a ScanMemoryPoolForCorruptions periódicamente. Llámalo en un solo lugar. ¿Tienes un error? Llámalo antes. Aún recibiste un error? Llámalo antes de nuevo. ¿No hay error? Tu problema se ubica en algún lugar entre esas últimas llamadas. Ahora puede usar la variable FullDebugModeScanMemoryPoolBeforeEveryOperation para obtener una ubicación precisa. Solo enciéndalo solo en el área de este código y apáguelo justo después.

Hay un error muy similar: "FastMM detectó que un bloque se ha modificado después de ser liberado". En este caso, su código no modifica las estructuras internas, sino otra memoria, que no se utiliza en absoluto ("memoria libre").

Por cierto, ¡su error no es doble! Si se trata de una llamada doble libre, FastMM le dirá eso explícitamente (es fácil de detectar, ya que está tratando de liberar el bloque de memoria no utilizado o no existente): "Se ha intentado liberar/reasignar un bloque no asignado ".

+0

Gracias Alexander. No tenía ni idea sobre "ScanMemoryPoolForCorruptions". Supongo que es una función que ofrece FastMM DLL. Iré a buscar sobre esto ahora mismo. – Ampere

+0

Esa es la función de FastMM4.pas estándar. Es de la versión completa independiente de FastMM. No existe en la versión de FastMM, que está integrada en Delphi. No hay una DLL en cuestión aquí. Esta es solo una función en el archivo pas habitual;) – Alex

+0

Lamentablemente, el enlace está muerto. Pero puede acceder a él en: http://web.archive.org/web/20091007162116/http://blog.eurekalog.com/?p=198 – EMBarbosa

4

Un El encabezado de bloque se corrompe por lo general significa que algo ha estado sobreescribiendo la memoria, por lo general haciendo algún tipo de operación insegura. ¿Estás usando punteros sin procesar o código ensamblador en alguna de tus tareas? Además, si tiene habilitada la comprobación de rango y la comprobación de límites, intente encenderlos y reconstruirlos. Pueden ayudar a atrapar muchos de este tipo de problemas.

+0

Hola Mason. Sin ASM, sin operación de puntero sin formato, la comprobación de rango está SIEMPRE activada. Esto es exactamente lo que estoy tratando de descubrir todo el día de hoy: donde podría sobreescribir ese maldito objeto. – Ampere

+1

Vi una situación como esta una vez antes. Eventualmente lo localicé en una biblioteca de terceros que estaba usando y estaba haciendo algunas operaciones con punteros crudos y buscando algunos de ellos. ¿Podría ser ese el caso aquí? –

+0

BTW no parece que no se sobrescriba el objeto, sino el encabezado del bloque de memoria. Pero para estar seguro, intente poner un punto de interrupción en el código de limpieza que le permita examinar el estado de este objeto antes de que se ejecute el destructor. Mírelo en el depurador y asegúrese de que sus campos sean válidos. (De lo contrario, puede usar un punto de interrupción de dirección para hacer que encontrar lo que sobrescriba su memoria sea trivial.) –

1

Un par de cosas y estoy preguntando porque no puedo ver su código.

Dado el siguiente código:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    wObjLst : TObjectList; 
begin 
    wObjLst := TObjectList.Create; 
    try 
     wObjlst.OwnsObjects := true; 
     wObjlst.Add(TPersistent.Create); 
     wObjlst.Add(TPersistent.Create); 
    finally 
     freeandnil(wObjlst); 
    end; 
end; 

Esto funciona con el error a cabo.

usted afirma que

At runtime, a form creates a TStringGrid and then the AsmJob which creates those two SAM objects (and load some data from disk in each of them). The AsmJob is also assigned to the grid. When the form is destroyed, the Grid takes care of the AsmJob by freeing it, which frees the TSam objects. Here is the problem: the first object is freed withot problems but the second one dies when its inherited method (in Destroy destructor) is called.

Mi primera pregunta es ¿cómo el AsmJob se asignan a TStringGrid para que el TStringGrid destruye la AsmJob, nos muestras?

En segundo lugar, ¿por qué crear un descendiente de TObjectList para que almacene dos objetos y luego liberarlos en lugar de crearlos usted mismo y dejar que TObjectList los destruya como se muestra arriba?

La otra cosa que debe intentar es descargar el paquete FastMM4 completo desde fastmm.sourceforge.net, instálelo y use el dll fulldebug para rastrear exactamente qué objeto está fallando. Tú y yo asumimos que es uno de los objetos SAM y podría ser o no serlo.

+0

Hola Ryan. Originalmente, ObjectList se configuró en OwnObj = true, pero ahora libero los objetos "manualmente" para ver dónde aparece el error. Así es como identifiqué que el error aparece en la invocación heredada (destrucción) de los objetos TSam. ¡DE TODOS MODOS! Si creo y uso los objetos TSam sin hacerlo manualmente (es decir, sin TAsmJob, que es una especie de administrador de estos objetos) todo funciona de maravilla. No tengo ningún error. -------- PD: Ya tengo FastMM en modo de depuración completa. – Ampere

2

Puede haber una carrera lógica en algún lugar del código donde se escribe un objeto mientras se libera. Agregue NULL-checks y otros mecanismos de IPC (listas de bloqueo, etc.) para asegurarse de que ese no sea el caso.

Otra opción podría ser subclasificar el código para agregarle un registro y comprobar si los objetos se están accediendo secuencialmente.

Cuestiones relacionadas