Siempre es incorrecto utilizar métodos o propiedades de una referencia nula, incluso si parece funcionar a veces.
FreeAndNil
de hecho no se puede utilizar para detectar doble frecuencia. Es seguro llamar al FreeAndNil
en una variable que ya no existe. Como es seguro, no ayuda a detectar nada.
Esto no es un error de puntero rancio. Este es un error de referencia nula. Un error de puntero rancio es cuando ha liberado un objeto pero no borró todas las variables que lo hicieron referencia. Entonces la variable aún conserva la dirección anterior del objeto. Esos son muy difíciles de detectar. Usted puede obtener un error tal como esto:
MStr := TMemoryStream.Create;
MStr.Free;
MStr.Size := 0;
También puede obtener uno como este:
MStr := TMemoryStream.Create;
OtherStr := MStr;
FreeAndNil(MStr);
OtherStr.Size := 0;
Usando MStr.Size
después de haber liberado el objeto MStr
hace referencia es un error, y se debe plantear una excepción. Si hace generar una excepción depende de la implementación. Tal vez lo haga, y tal vez no sea así. Sin embargo, no es aleatorio.
Si está buscando un error doblemente libre, puede usar los asistentes de depuración que proporciona FastMM, como otros han sugerido también. Funciona al no liberar la memoria de nuevo al sistema operativo, o incluso volver al grupo interno de memoria libre de Delphi. En su lugar, escribe datos mal conocidos en el espacio de memoria del objeto, por lo que cuando vea esos valores, sabrá que está leyendo algo que ya ha liberado. También modifica el VMT del objeto para que la próxima vez que llame a un método virtual en esa referencia de objeto, obtenga una excepción predecible, e incluso le dirá qué objeto supuestamente liberado intentó usar. Cuando intenta liberar el objeto nuevamente, puede indicarle no solo que ya lo liberó, sino también dónde fue liberado la primera vez (con un seguimiento de la pila) y dónde fue asignado.También recopila esa información para informar sobre fugas de memoria, donde liberaste un objeto menos de una vez en lugar de más.
También son hábitos que se pueden utilizar para evitar el problema de futuro código:
- reducir el uso de variables globales. Una variable global podría ser modificada por cualquier código a lo largo del programa, lo que le obligará a preguntarse cada vez que lo use, "¿El valor de esta variable sigue siendo válido o algún otro código ya lo ha liberado?" Cuando limita el alcance de una variable, reduce la cantidad de código que debe considerar en su programa cuando busca razones por las cuales una variable no tiene el valor que espera.
- Sea claro sobre a quién pertenece un objeto. Cuando hay dos piezas de código que tienen acceso al mismo objeto, necesita saber cuál de esas piezas de código posee el objeto. Es posible que cada uno tenga una variable diferente para hacer referencia al objeto, pero todavía hay un solo objeto allí. Si un fragmento de código llama al
FreeAndNil
en su variable, aún deja la variable del otro código sin cambios. Si ese otro código cree que posee el objeto, entonces estás en problemas. (. Este concepto de propietario no está necesariamente ligada a la propiedad TComponent.Owner
No tiene por qué ser un objetoque lo posee, sino que podría ser un subsistema general de su programa.)
- No mantener las referencias a persistentes objetos que no son de su propiedad. Si no mantiene referencias de larga duración a un objeto, entonces no tiene que preocuparse de si esas referencias siguen siendo válidas. La única referencia persistente debe estar en el código que posee el objeto. Cualquier otro código que necesite usar ese objeto debería recibir una referencia como parámetro de entrada, usar el objeto y luego descartar la referencia cuando devuelve su resultado.
creo que 'alguien' le faltan algunos conceptos importantes. –
Como dije antes, FastMM tiene una opción que hace lo que usted describe. Rob señala que sobrescribirá la memoria con "números mágicos" para que pueda detectar este tipo de errores. Mira esto. Descargue FastMM4 completo y habilite el registro en el archivo. Lo he encontrado bastante útil. – Vegar
FreeAndNil() no anula la memoria ocupada por la instancia, elimina la referencia pasada. – Bevan