Comprensión y prevención de fugas de memoria

El soporte de Delphi para la programación orientada a objetos es rico y poderoso. Las clases y los objetos permiten la programación de código modular. Junto con componentes más modulares y más complejos vienen errores más sofisticados y complejos..

Si bien desarrollar aplicaciones en Delphi es (casi) siempre divertido, hay situaciones en las que sientes que todo el mundo está en tu contra.

Siempre que necesite usar (crear) un objeto en Delphi, debe liberar la memoria que consumió (una vez que ya no era necesario). Seguramente, los bloques de protección de memoria try / finalmente pueden ayudarlo a evitar pérdidas de memoria; aún depende de usted proteger su código.

Se produce una pérdida de memoria (o recurso) cuando el programa pierde la capacidad de liberar la memoria que consume. Las fugas repetidas de memoria hacen que el uso de memoria de un proceso crezca sin límites. Las pérdidas de memoria son un problema grave: si tiene un código que causa pérdidas de memoria, en una aplicación que se ejecuta las 24 horas, los 7 días de la semana, la aplicación consumirá toda la memoria disponible y finalmente hará que la máquina deje de responder.

Fugas de memoria en Delfos

El primer paso para evitar pérdidas de memoria es comprender cómo ocurren. Lo que sigue es una discusión sobre algunas trampas comunes y mejores prácticas para escribir código Delphi sin fugas.

En la mayoría de las aplicaciones (simples) de Delphi, donde usa los componentes (botones, notas, ediciones, etc.) que suelta en un formulario (en tiempo de diseño), no necesita preocuparse demasiado por la administración de la memoria. Una vez que el componente se coloca en un formulario, el formulario se convierte en su propietario y liberará la memoria tomada por el componente una vez que el formulario se cierra (destruye). Form, como propietario, es responsable de la desasignación de memoria de los componentes que alojó. En resumen: los componentes de un formulario se crean y destruyen automáticamente

Ejemplos de fugas de memoria

En cualquier aplicación de Delphi no trivial, querrá instanciar componentes de Delphi en tiempo de ejecución. También tendrá algunas de sus propias clases personalizadas. Digamos que tiene una clase TDeveloper que tiene un método DoProgram. Ahora, cuando necesita usar la clase TDeveloper, crea una instancia de la clase llamando al Crear método (constructor). El método Create asigna memoria para un nuevo objeto y devuelve una referencia al objeto..

var
zarko: TDeveloper
empezar
zarko: = TMyObject.Create;
zarko.DoProgram;
final;

Y aquí hay una pérdida de memoria simple!

Cada vez que crea un objeto, debe deshacerse de la memoria que ocupaba. Para liberar la memoria de un objeto asignado, debe llamar al Gratis método. Para estar completamente seguro, también debe usar el bloque try / finally:

var
zarko: TDeveloper
empezar
zarko: = TMyObject.Create;
tratar
zarko.DoProgram;
finalmente
zarko.Free;
final;
final;

Este es un ejemplo de asignación segura de memoria y código de desasignación.

Algunas palabras de advertencia: si desea crear una instancia dinámica de un componente Delphi y liberarlo explícitamente en algún momento posterior, siempre pase nulo como propietario. De lo contrario, puede introducir riesgos innecesarios, así como problemas de rendimiento y mantenimiento del código..

Además de crear y destruir objetos usando los métodos Crear y Gratis, también debe tener mucho cuidado al usar recursos "externos" (archivos, bases de datos, etc.).
Digamos que necesita operar en algún archivo de texto. En un escenario muy simple, donde el método AssignFile se usa para asociar un archivo en un disco con una variable de archivo cuando haya terminado con el archivo, debe llamar a CloseFile para liberar el identificador de archivo para comenzar a usarlo. Aquí es donde no tienes una llamada explícita a "Gratis".

var
F: archivo de texto;
S: cuerda;
empezar
AssignFile (F, 'c: \ somefile.txt');
tratar
Lectura (F, S);
finalmente
Cerrar archivo (F);
final;
final;

Otro ejemplo incluye cargar archivos DLL externos desde su código. Siempre que use LoadLibrary, debe llamar a FreeLibrary:

var
dllHandle: THandle;
empezar
dllHandle: = Loadlibrary ('MyLibrary.DLL');
// hacer algo con esta DLL
si dllHandle 0, entonces FreeLibrary (dllHandle);
final;

Fugas de memoria en .NET?

Aunque con Delphi para .NET el recolector de basura (GC) gestiona la mayoría de las tareas de memoria, es posible tener pérdidas de memoria en las aplicaciones .NET. Aquí hay un artículo de discusión GC en Delphi para .NET.

Cómo luchar contra las fugas de memoria

Además de escribir código modular seguro para la memoria, se pueden evitar pérdidas de memoria mediante el uso de algunas de las herramientas de terceros disponibles. Las herramientas de reparación de fugas de memoria de Delphi lo ayudan a detectar errores de aplicación de Delphi, como corrupción de memoria, fugas de memoria, errores de asignación de memoria, errores de inicialización variable, conflictos de definición variable, errores de puntero y más.