Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Liberar memoria al borrar componentes en runtime (https://www.clubdelphi.com/foros/showthread.php?t=89633)

mjjj 31-12-2015 11:48:01

Liberar memoria al borrar componentes en runtime
 
Estimados, utilice Delphi XE5 para desarrollar una aplicación que se conecta a un servidor Datasnap para adquirir datos de una DB.
La aplicación es un Dashboard tipo las pantallas que están en los aeropuertos para notificar sobre los vuelos.
En tiempo de ejecución se crea un panel principal en el cual se van creados un Frame previamente creado con la información de la DB. Estos paneles creados en runtime están contenidos en otro panel fijo (panel6) en le formulario principal.
En caso de tener muchos datos que mostrar, puede que se creen (siempre en runtime) más de un panel que contenga los frames.
El último dato que debo señar es que cada vez que se actualizan los datos, primero libero todos las paneles, y luego continuo con la creación de los mismos más los respectivos frames.
En una misma rutina se llevan a cabo las 2 funciones... liberar y crear paneles y frames.

El problema está en la memoria que utiliza la aplicación, ya que es un programa que deberá estar corriente 24/7.
Al transcurrir el tiempo la cantidad de memoria que utiliza la aplicación va en aumento, en ningún momento se reduce.

Adjunto código de liberación y creación.

Código Delphi [-]
/// borrado
for I := panel_total downto 1 do
begin
PanelDinamico := findcomponent('paneldinamico'+inttostr(i)) as Tpanel;
if assigned (PanelDinamico) then
PanelDinamico.free;
end;

/// creacion
i := 0;
panel_total := 1;
while not buscar.EOF do
begin
inc(i);

if i = 9 then  /// 8 frames por panel
begin
inc(panel_total);
i := 1;
end;


if i = 1 then
begin
PanelDinamico := TPanel.Create(self);
PanelDinamico.Name:= 'paneldinamico' + inttostr(panel_total) ;
PanelDinamico.Parent := panel6;
PanelDinamico.Top := 0;
PanelDinamico.Left := 0;
PanelDinamico.Width := panel6.Width;
PanelDinamico.Height := panel6.Height;
PanelDinamico.BevelOuter:= bvnone;
end;

frame := TFrame3.Create(paneldinamico);
frame.Name:= 'frame' + inttostr(panel_total)+inttostr(i) ;
frame.Parent := PanelDinamico;
frame.ParentBackground := false;
frame.Width:= PanelDinamico.Width;
frame.Top:= 70 * (i - 1);
frame.Left:= 0;

//// carga de datos .....
end; /// fin del while

Están bien los procedimientos para crear y liberar estos componente?
Porque no se libera memoria una vez que se borran?

Espero me puedan ayudar.
Saludos

Ñuño Martínez 31-12-2015 12:03:22

Creo que el problema está en la creación, ya que puede que crees más marcos (frames) de los que realmente quieres, por eso aumenta de tamaño de forma contínua. El código lo veo complicado. Creo que deberías buscar el índice (panel_total) primero y crear el panel fuera del bucle.

AgustinOrtu 31-12-2015 15:49:43

En que momento deberian liberarse los paneles y los frames?

Yo no usaria FindComponent

Por que mejor no mantener una estructura con toda informacion? Una lista, cola, o pila segun las necesidades

Dentro de los frames metes "algo"?

Prueba a ejecutar la aplicacion usando ReportMemoryLeaksOnShutdown := True

Te va a decir si hay fugas de memoria (memory leaks) y el nombre de los objetos, aunque buscar la fuga es tu trabajo y es a veces, bastante pesado

Osorio 31-12-2015 16:05:23

Si solo vas a motrar datos sin ningun proceso complejo puedes considerar la opcion de usar un componente que se llama TDBCtrlGrid que esta en la paleta de Data Controls. Este hace todo el trabajo sucio y te descomplicas con la creacion y liberacion de componentes en tiempo de ejecución.

mjjj 31-12-2015 19:16:29

Gracias por sus consejos, pero el programa realiza todo lo que necesito, solo que eternamente mientras este en ejecución aumenta el uso de memoria.

Se crean la cantidad de frames adecuados dentro del panel correspondiente, esto porque en caso de tener, por ejemplo 20 registros, y en cada panel solamente puedo contener 8 registros (frames), necesito mostrar, por ejemplo, durante 10 segundos un panel y luego pasar al que viene, y así hasta completar el loop completo, y en ese momento actualizar la información... solo en este momento se consulta al servidor datasnap, para evitar estar conectado todo el tiempo, ya que la aplicación se ejecutará alejado geográficamente del servidor, donde eventualmente tiene mala conectividad.

Otra cosa, siempre libero los paneles antes de comenzar a crear los panes que contienen a los frames, y creo todos los paneles necesario para mostrar los registros correspondiente, pero uno sobre otro, y el loop lo unico que hace es bringtofront al panel que corresponda. Alguna otra idea para esto??

Mi problema es que me percaté del tema de la memoria, entonces mi pregunta va por el lado de saber si está bien realizado la creación y liberación de los componentes... nótece que solo libero los paneles, ya que los frames están contenidos en el panel de creación en ejecución, y esto se crean "self"... esto esta bien?? creo que si, pero no estoy seguro.

Como puedo liberar los panales sin el findcomponent??

Uffff... hartas preguntas, espero me puedan ayudar.
Saludos

AgustinOrtu 31-12-2015 21:28:50

No se quien es "self" ya que no pusiste que clase ejecuta el codigo

Probablemente sea un form; osea que el panel va a ser liberado:

1. Cuando hagas panel.Free
2. Cuando se libere el form

Otra opcion seria no liberar los paneles, sino que reusarlos; actualizar o modificar la info y solo descartar todo cuando se cierra la aplicacion.



Otro gran problema es FindComponent. No tengo delphi a mano para probar, pero estoy seguro que FindComponent no encuentra lo que fue creado en runtime; solo lo de tiempo de diseño

Por ejemplo,

Código Delphi [-]
  AlgunForm.Components[] --> array de componentes, en tiempo de diseño
  AlgunForm.Controls[]  --> array de controles, incluye los componentes y tambien lo creado en tiempo de ejecucion

Debido a esto apuesto a que FindComponent se comporta de manera similar

Lo puedes depurar facilmente,

Código Delphi [-]

/// borrado
for I := panel_total downto 1 do
begin
  PanelDinamico := findcomponent('paneldinamico'+inttostr(i)) as Tpanel;
  if assigned (PanelDinamico) then
    PanelDinamico.free; -> punto de ruptura aca, o un showmessage ,para ver si entra al if, yo estoy seguro que no
end;

Como te decia, deberia ejecutar la aplicacion con ReportMemoryLeaksOnShutdow := True, asignalo en el OnCreate del form principal o en el inicio de la aplicacion (.dpr); esto te va a decir que objetos no estan siendo liberados, aunque tomarlo con pinzas: el que sean liberados no te garantiza que sean liberados cuanto tu quieres que sean liberados; me explico, como estas creando los paneles con un Owner (Self, el form) quiere decir que cuando muere el form, mueren los paneles, pero lo interesante en tu caso es que se liberen antes

La forma mas comoda para liberar los paneles en tu caso es, creas una simple lista y metes todos los paneles ahi, y luego simplemente la recorres y vas liberando

Casimiro Notevi 31-12-2015 22:31:05

Cita:

Empezado por AgustinOrtu (Mensaje 500932)
...

Son "truquitos" que se aprenden con la experiencia ^\||/


La franja horaria es GMT +2. Ahora son las 03:35:08.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi