Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Memoria (https://www.clubdelphi.com/foros/showthread.php?t=2209)

susje 14-07-2003 15:17:17

Memoria
 
Buenas a todos:

¿Alguien me puede explicar como puedo hacer que una aplicacion en delphi no aumente de memoria tanto?
Creo que estoy cerrando todos los objetos, pero la aplicacion sigue subiendo de memoria hasta el limite que da el error de "out of memory".


Saludos.

marcoszorrilla 14-07-2003 16:26:25

No explicas mucho que es lo que haces y no es normal que te ocurra lo que nos cuentas.

Para empezar, mira a ver cuantas Formularios tienes en AutoCreate, no debieran pasar de 2 ó 3, el resto tendrías que pasarlos a disponibles "Available", y solamente crearlos cuando vayan a utilizarse.

.......

Un Saludo.

delphi.com.ar 14-07-2003 16:29:13

No es la solución, pero te recomiendo leer este hilo http://www.clubdelphi.com/foros/show...=&threadid=253

Saludos!

guillotmarc 14-07-2003 17:21:46

Hola.

Tal vez tengas una fuga de memória. Los componentes visuales, tienen una propiedad parent que indica quien es el responsable de liberarlo. De forma que al eliminar un formulario, se libera la memória de todos los componentes que lo tengan como parent.

Aunque a veces se crean objetos por código, los cuales se tienen que liberar también por código mediante el método Free, puesto que al liberar el formulario donde se crearon, no implica que se libere su memória asignada. Esto puede provocar que cada vez que cargas el formulario, se creen objetos nuevos por código, los cuales al no liberarse nunca, van incrementado gradualmente la memória consumida.

Ejemplo :

Código:

procedure TfrmAnomalia.CargarImagen;
var Jpeg:TJpegImage;
    Corriente:TMemoryStream;
begin
  imgFoto.Picture := nil;
  if cdsDatosIMAGEN.BlobSize > 0  then begin
    Jpeg:=TJpegImage.create;
    Corriente:=TMemoryStream.create;
    try
      cdsDatosIMAGEN.SaveToStream(Corriente);
      Corriente.Seek(0,soFromBeginning);
      Jpeg.LoadFromStream(Corriente);
      imgFoto.Picture.Assign(Jpeg);
    finally
      Jpeg.Free;                  (*)
      Corriente.Free;            (*)
    end;
  end;
end;

Estas líneas, cargan en un TImage, una imagen en formato Jpeg guardada en un campo Blob. En los (*) se muestra como libero unos objetos creados por código. Si no lo hiciese, cada vez que cargase el formulario, tendría una perdida de memória, con el contenido de la imagen.

No estaría de más que revisases tu código buscando objetos sin liberar.

Saludos.

delphi.com.ar 14-07-2003 18:21:12

Cita:

Posteado originalmente por guillotmarc
Los componentes visuales, tienen una propiedad parent que indica quien es el responsable de liberarlo.
Pero cuando tienes un TControl que no tiene Parent, o cualquier objeto heredado de TComponent, el que se encarga de eliminarlo es el Owner.

Saludos!

guillotmarc 14-07-2003 18:45:50

Hola.

El problema normalmente aparece con los objetos que no heredan de TControl o TComponent (o sea los no visuales), o los componentes visuales que se hayan creado por código (y por lo que no se asigna esa propiedad a menos que se indique especificamente).

NOTA : Seguramente habré confundido la propiedad Parent por la Owner, y ser este ultimo, como comentas, el responsable de la liberación del objeto.

Saludos.

delphi.com.ar 14-07-2003 18:57:29

Entiendo a lo que apuntas, como suena medio raro tu aclaración, te comento que yo entiendo por "componentes visuales", aquellos heredados de TControl, ya sea TGraphicControl o TWinControl, en estos podemos utilizar Parent para la "auto-eliminación", y más arriba en la jerarquía, con los TComponents podemos utilizar Owner. En los TControls la propiedad Parent asume la funcionalidad de Owner al liberar todos su "hijos"... De todos modos me parece mas prolijo encargarse explícitamente de liberar los objetos no utilizados.


Saludos!

delphi.com.ar 14-07-2003 19:01:28

Ahhh... me has cambiado el texto!!!... Ahora es en vano la aclaración que he hecho....


Saludos!

PD: :D Aún conservo una copia de tu texto anterior :D

guillotmarc 14-07-2003 19:16:15

Jejeje.

Lo siento, suelo releer los mensajes que envío, y muchas veces modifico lo que no me acaba de gustar. :D :D

Un saludo.

Eduardo 17-07-2003 13:50:05

Hola, acabo de unirme a este foro. Antes de nada presentarme, hace años si usaba clubdelphi de forma habitual pero un cambio de trabajo y de vida hicieron que lo dejara. Ahora vuelvo y espero poder ayudar y recibir ayuda en delphi.
He leido los problemas de memoria de los que hablais. A mi me pasa lo mismo, trabajo con formularios que crean frames que crean controles en tiempo de ejecucion y cuando abro el formulario unas 10 veces a la onceaba dice que le falta memoria. Llevo bastante intentando buscar la solucion. En el frame he probado a poner
private
{ Private declarations }
Destructor Destroy; override;
Destructor tfr_camposb.Destroy;
begin
while controlcount <>0 do controls[0].free;
while componentcount <>0 do components[0].free;
inherited Destroy;
end;
y en el formulario lo mismo pero sigo con los mismos problemas. La cosa esta en que no se el nombre de los controles porque se crean a partir de los campos de la base de datos y en funcion de otras condiciones algo mas complicadas.
Tampoco tengo la certeza de cual no se esta destruyendo y donde se come la memoria. Si le hago una traza, pasa por los free y los ejecuta. He probado con el winsight para ver si me dice algo y nada. ¿como puedo saber que se ha quedado sin destruir? ¿teneis algun truco para saberlo?

Estaba trabajando con delphi 5 y ahora lo he compilado con delphi 7 y sigue con los mismos problemas.

Gracias por cualquier sugerencia.

guillotmarc 17-07-2003 14:33:28

Hola.

La sobreescritura que haces del método Destroy no es necesaria. Puesto que solo liberas los componentes que ya tienen asignado Parent o Owner, dado que són los unicos que te saldrán en la colección Controls y Components respectivamente. Y estos controles y componentes ya són liberados automaticamente al liberar el formulario.

Lo que tendrías que buscar són controles y componentes que hayas creado, y a los que no asignas correctamente su padre (en Parent o Owner). Puesto que estos son los que al liberarse el padre, no serán liberados automaticamente. También puedes tener objetos (no controles o componentes) creados en el código, los cuales se tienen que liberar una vez usados, como en el ejemplo que puse con objetos de la clase TJpegImage y TMemoryStream.

Saludos.

delphi.com.ar 17-07-2003 15:48:57

Insisto con esto http://www.marteens.com/trick42.htm

Eduardo 17-07-2003 17:22:01

Hola
No es por no ir, como dirian unos humoristas españoles, pero ir por ir ....

No es este el caso, el caso es que llevo 2 años desarrollando sobre la misma aplicacion, es practicamente una herramienta para hacer aplicaciones de gestion. Crea automaticamente los formularios, relaciones, integridades referenciales, etc. Imaginate la cantidad de codigo. Por eso me gustaria saber si existe algun truco, alguna manera de listar los controles y/o los componentes sin 'padre'. De esta forma veria rapidamente donde puede estar el problema y al mismo tiempo nos serviria para futuros desarrollos. Se pondria como una especie de control antes de la salida de la aplicacioin que avise al programador de que lo que ha echo no esta bien. Hombre! si delphi o alguna utilidad tuviera esa prestacion, yo la he buscado en el winsight y no lo he localizado, no haria falta ese lio.

Gracias por cualquier comentario

guillotmarc 17-07-2003 18:52:47

Hola.

Hay algunos programas para detectar estas fugas de memória. Por ejemplo el MemProof de Atanas Stoyanov.

http://www.automatedqa.com/

En la web hay su catálogo de programas comerciales de testeo de aplicación, pero en Downloads puedes descargar gratuitamente el MemProof.

Saludos.

jachguate 17-07-2003 19:22:28

De cualquier forma no vas a poder detectar automáticamente los controles sin parent o los componentes sin owner.

Lo que podes hacer es ubicar, con grep o con una busqueda es ubicar todas las llamadas a Create, y aunque te lleve un buen tiempo, revisar que siempre se asigne el parent y el owner.

De hecho, con los componentes, el owner regularmente se asigna en la llamada al constructor, digamos una llamada de la forma

Código:

Procedure TForm1.CrearObjetos;

Var
  ComponenteX : TMiComponente;

Begin
  ComponenteX := TMiComponente.Create(Self);
end;

Asigna la instancia de Form1 como owner de ComponenteX;

Será tedioso, pero es necesario.

Hasta luego.

;)

Eduardo 18-07-2003 20:34:56

Ante todo, gracias a todos los que me habeis ayudado.

Por fin he dado con el problema

Como decia al principio, mi aplicacion se basa en formularios que se crean en tiempo de ejecucion.

Las tablas las tengo puestas en frames, de forma que por ejemplo, la tabla de facturas esta en un frame que tiene la misma tabla, el datasource y las tablas que tienen relacion, en este caso, la de clientes, forma de pago, etc.

Si este frame contenedor de tabla tiene alguna relacion algo mas fuerte con otro frame, por ejemplo, el de facturas con las lineas de facturas, lo que hago es colocar dentro del frame de facturas el frame de lineas de facturas, y dentro de este ultimo el de movimientos de almacen, con lo cual me llevo todas las posibles relaciones ya creadas. Esta filosofia, que a simple vista puede resultar complicada, luego es muy efectiva. Yo he trabajado con datamodules durante varios años y los problemas eran horrorosos. Con frames todo funciona como la seda. Si en un caso especial quiero acudir a la tabla solo sin sus relaciones esenciales, pues la pongo y punto, este es el caso de que quiera consultar unos totales de factura pero en ese caso no me interesen los datos de clientes o forma de pago. De la misma forma, si quiero usar la tabla con todas sus relaciones, pongo el frame en lugar de la tabla y heredo todo.

Los formularios lo que hacen es leerse los frames con las tablas, los campos y las relaciones y crean mantenimientos.

Yo pensaba que se me habia ido destructores en estos formularios, es decir, que creaba los controles y luego no los destruia. Y me he vuelto loco buscandolos.

El problema era mas sencillo de lo que parecia. He cojido el memprof que me habeis aconsejado y lo he ejecutado contra mi aplicacion. Es impresionante, y para mi al mismo tiempo era desconsolador, unos formularios perdian memoria y otros no sin razon aparente. Al final vi una opcion en el memprof que me permitia ver las tablas abiertas, y descubro que si un formulario abre por ejemplo 30 tablas, al cerrarlo solo me cierra 23, cuando otro si lo hace bien. Yendo por este camino descubri que unos de mis frames preferidos le creaba un frame dentro de este en tiempo de ejecucion y con un create(nil) ¡toma ya!. He reconstruido el codigo para que lo creara correctamente y ya funciona todo de maravillas.

Guardare el memprof a buen recaudo. Es una herramienta imprescindible. Por cierto, que ese programa que tanto publican en esta misma web de testeo pero que tiene coste. Esta en ingles y mi ingles es bastante pobre. Alguien me puede orientar o darme alguna direccion web en español donde pueda aprender.

Gracias de nuevo

delphi.com.ar 18-07-2003 21:04:26

Aha!!... esos es una demostración de que no hay que echarle la culpa al lenguaje hasta no estar seguros de quien es el culpable!! :D

Te agrego que cuando jachguate escribió su mensaje, yo estaba por "refutarlo" (porque lo había malentendido) diciendo que si un componente pertenece a un form o cualquier otro componente, estamos "obligados" a asignarle el owner, si es que queremos ser prolijos.
Agrego otro tema que me parece muy importante, y he visto muchos programadores experimentados que lo pasan por alto:

Cuando creamos una instancia de un objeto que vamos a eliminar en el mismo procedimiento, es MUY IMPORTANTE que escribamos un try...finally para siempre liberarlo.

Código:

var
  MiObj: TObject;
begin
  MiObj := TObject.Create;
  Try
    ...
  finally
    MiObj.Free;
  end;

Saludos!!

jachguate 18-07-2003 23:32:07

Cita:

Posteado originalmente por delphi.com.ar

Te agrego que cuando jachguate escribió su mensaje, yo estaba por "refutarlo"

Por re--- queeeee?????

recorcholis...

:D :D

Hasta luego.

pd. Crei que me estabas maltratando... porque te habia malentendido... jejejeje

:D
;)

susje 23-07-2003 00:07:10

Hola a todos,
Acabo de ver los mensajes y me he decido a descargar el programa MemProf pero creo que no lo se utilizar del todo bien
¿Alguien me puede explicar cual es su funcionamiento?¿Como puedo ver los objetos que no liberan memoria?.

Saludos.


La franja horaria es GMT +2. Ahora son las 12:20:44.

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