Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Optimizacion del Uso de la memoria (https://www.clubdelphi.com/foros/showthread.php?t=66884)

rmora 17-03-2010 04:32:31

Optimizacion del Uso de la memoria
 
Hola amigos,
Tengo una aplicacion en delphi5 en la cual estoy optimizando el uso de la memoria. Ahora bien, para liberar la memoria que utilizan mis formularios estoy utilizando las siguientes sentencias en el evento Close de cada formulario:

procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action := caFree;
FrmVentasClienteExpress := Nil;
FrmVentasClienteExpress.Free;
end;


En mis consultas estoy utilizando lo siguiente:

qry1:= CrearConsulta ('SELECT CUENTA FROM FACTURA_BISTRO WHERE ESTATUS > 0 AND CUENTA_PRINCIPAL = "' + qry1.fieldbyname('CUENTA').AsString + '"');
result := qry2.RecordCount > 0;
qry1 := Nil;
qry1.Free;

Mi consulta en base a esto es la siguiente: Estoy utilizando de buena manera el codigo para optimizar el uso de la memoria??.

Ñuño Martínez 17-03-2010 09:38:37

Cita:

Empezado por rmora (Mensaje 357229)
Mi consulta en base a esto es la siguiente: Estoy utilizando de buena manera el codigo para optimizar el uso de la memoria??.

No.











Vaaaaale, te daré una pista.

Fíjate que primero estás asignando "Nil" a la variable y después llamas a "Free". Piénsalo.

(Disculpa la broma :D)

mcs 17-03-2010 10:10:34

Cita:

Empezado por rmora (Mensaje 357229)

FrmVentasClienteExpress := Nil;
FrmVentasClienteExpress.Free;

Lo normal sería que esto te tirase una Error Access Violation Exception... Si lo haces al revés (primero el Free y luego asignar el Nil), tiene que funcionar.

De todas formas, en una época dónde la cantidad de RAM se mide en gigas y ya hay discos duros de terabyte, vale la pena perder el tiempo en salvar una docena de kbytes? (Programando en microcontroladores ya es otra cosa...)

Ñuño Martínez 17-03-2010 10:32:07

Cita:

Empezado por mcs (Mensaje 357258)
De todas formas, en una época dónde la cantidad de RAM se mide en gigas y ya hay discos duros de terabyte, vale la pena perder el tiempo en salvar una docena de kbytes?

Por supuesto que sí. ¡Menuda pregunta! :eek:

Te pongo un ejemplo. Estoy trabajando en una tienda web en PHP. Las facturas las genera y almacena en disco en formato PDF. Pues bien, si intenta generar más de una factura en una tanda no nos lo permite por falta de memoria. Incluso aumentando el límite impuesto por PHP y Apache a 132 Mib (que es una burrada para una aplicación web) no permite generar más de ocho facturas de una única página. Y el problema es que tampoco permite hacer más de ocho incluso generándolas una a una, guardándolas en disco y eliminando el objeto con "unset" nada más guardarla, antes de generar la siguiente. ¿La razón? Simple: quien diseñó la clase que utilizamos para generar el PDF (no lo hemos hecho nosotros) pensó que no era tan importante optimizar la memoria, de forma que cada vez que se utiliza deja un montón de datos "huérfanos" que ocupan varias decenas de megas por documento, y al final revienta.

No nos engañemos porque nuestra computadora tenga cientos de gigas de memoria y varios teras en la partición de intercambio: la memoria sigue siendo y será siempre un bien preciado y debe ser utilizado con cabeza.

mcs 17-03-2010 10:47:04

Cita:

Empezado por Ñuño Martínez (Mensaje 357260)
No nos engañemos porque nuestra computadora tenga cientos de gigas de memoria y varios teras en la partición de intercambio: la memoria sigue siendo y será siempre un bien preciado y debe ser utilizado con cabeza.

Por supuesto que la memoria es y será siempre un bien preciado, pero a lo que yo me refiero es que con "programar con cabeza" es suficiente.

Todavía soy muy novato en Delphi (lo mio era Java y VB.NET), y por lo que veo, por norma general los forms son creados en memoria cuando se inicializa la aplicación (no es como el java, que lo normal era form=new MiJFormulario(); form.showModal(); form=null), y por tanto es el propio Delphi quien lo destruye.

En otras palabras, yo soy partidario de destruir/liberar ÚNICAMENTE lo que yo he creado. Si lo ha hecho el IDE, o una clase por mi, debe ser el IDE o la citada clase quien libere los recursos que ha pedido.

Saludos,

Marc

Casimiro Noteví 17-03-2010 13:11:03

Cita:

Empezado por mcs (Mensaje 357263)
[..]En otras palabras, yo soy partidario de destruir/liberar ÚNICAMENTE lo que yo he creado. Si lo ha hecho el IDE, o una clase por mi, debe ser el IDE o la citada clase quien libere los recursos que ha pedido.
Saludos,
Marc

Es así.

Tú sólo tienes que liberar lo que tú has creado.
En tu caso:
Código:

procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
      Action := caFree;
//  FrmVentasClienteExpress := Nil;
//  FrmVentasClienteExpress.Free; 
end;

Código:

qry1:= CrearConsulta ('SELECT CUENTA FROM FACTURA_BISTRO WHERE ESTATUS  > 0 AND CUENTA_PRINCIPAL = "' + qry1.fieldbyname('CUENTA').AsString +  '"');
result := qry2.RecordCount > 0;
//qry1 := Nil;
//qry1.Free;

Y este caso, si qry1 es un query que has creado tú, puedes eliminarlo con:
Código:

FreeAndNil(qry1)
Y fíjate en lo que te ha dicho Ñuño, primero free, luego pones a nil

coso 17-03-2010 13:41:14

Hola,
Código Delphi [-]
procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action := caFree;
FrmVentasClienteExpress := Nil;
FrmVentasClienteExpress.Free;
end;

creo que aqui iria mejor el .Release. Un saludo.

PD: self.release incluso, aunque estes trabajando con solo una instancia de TFrmVentasexpress.
PDD: mas o menos lo que dijo casimiro en su primer parrafo :)

rmora 17-03-2010 17:14:45

Efectivamente Casimiro, Los formularios los creo Yo segun este codigo:

If not Assigned(FrmVentasClienteExpress) then
FrmVentasClienteExpress := tFrmVentasClienteExpress.Create(Self);

Luego lo muestro y posteriormente en el Close desearia liberar la memoria

Si lo hago segun este codigo me despliega un mensaje de "access violation":

procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action := caFree;
FrmVentasClienteExpress.Free;
FrmVentasClienteExpress := Nil;
end;

Pero si lo hago de esta manera funciona:

procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action := caFree;
FrmVentasClienteExpress := Nil;
FrmVentasClienteExpress.Free;
end;

No se si de esa manera el Free posterior al nil esta sobrando osea dejar algo asi:

procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;
var Action: TCloseAction);
begin
Action := caFree;
FrmVentasClienteExpress := Nil;
end;


Tambien estuve utilizando este codigo:

If not Assigned(FrmVentasClienteExpress) then
FrmVentasClienteExpress := tFrmVentasClienteExpress.Create(Self);
Try
FrmVentasClienteExpress.ShowModal;
finally
FrmVentasClienteExpress.Free;
FrmVentasClienteExpress := Nil;
end;
Aca el problema esta en que si ocurre una excepcion el sistema se queda congelado "pegado" y hay que volcar la tarea desde el administrador de tareas de windows.

Que piensan.....

Gracias por la valiosa ayuda!!!

afunez2007 17-03-2010 17:33:09

Normalmente yo uso lo siguiente:

Para formularios mdi creados desde el menu o de una barra de herramientas:

Código Delphi [-]
   ///Para Crearlos
    if not Assigned(tuForm) then //SI El form no esta creado
    Begin
        tuForm:= TtuForm.Create(nil);
    END
    ELSE;
       tuForm.Show;
       tuForm.WindowState:=wsMaximized;
    End;
    ///Para Liberarlos en el evento OnClose
    FreeAndNil(tuForm);

Si son formularios Modales:
Código Delphi [-]
///Se crea y se Libera desde el mismo evento en el menu o en la barra de herramientas
  tuForm:= TtuForm.Create(nil);
  Try
      tuForm.ShowModal;
  Finally
      FreeAndNil(tuForm);
  End;

Espero te sirvan, recuerda que deben estar quitados de la autocreacion del proyecto.

Saludos

rmora 17-03-2010 17:49:56

aFunez, gracias por tus comentarios.

En el caso de los formularios modales en el evento Close, pones algo?, que pasa si hay una excepcion?, el sistema se queda pegado?.

En los formularios mdi basta con la linea que me indicas o hay algo mas?.

Ahora es necesario que al crear los fomularios utilice "nil" en lugar del "self"?

Casimiro Noteví 17-03-2010 17:50:24

De este modo sólo debes dejar el caFree, lo otro sobra.

Código:

procedure TFrmVentasClienteExpress.FormClose(Sender: TObject;var Action: TCloseAction);
begin
  Action := caFree;
//  FrmVentasClienteExpress := Nil;
//  FrmVentasClienteExpress.Free;
end;

Y esto también es correcto, yo lo uso cuando necesito coger el valor de alguna variable o dato del form que se está cerrando... PERO, no uses caFree en el form frmVentasclienteExpress porque estarías igualmente liberando con free y poniendo a nil algo que ya no existe, debes usar, por ejemplo, caHide, esto te oculta el form y luego lo liberas tal y como haces o con freeandnil

Código:

If not Assigned(FrmVentasClienteExpress) then
  FrmVentasClienteExpress :=  tFrmVentasClienteExpress.Create(Self);
Try
  FrmVentasClienteExpress.ShowModal; //  <-- en ese form no uses caFree, usa caHide
finally
  FrmVentasClienteExpress.Free;
  FrmVentasClienteExpress := Nil;
end;


Ñuño Martínez 17-03-2010 18:17:12

Cita:

Empezado por rmora (Mensaje 357297)
Ahora es necesario que al crear los fomularios utilice "nil" en lugar del "self"?

Depende de si quieres que el componente sea destruido por su contenedor o si quieres controlar tú diréctamente cuándo destruirlo.

afunez2007 17-03-2010 18:20:43

Cita:

Empezado por rmora (Mensaje 357297)
aFunez, gracias por tus comentarios.

En el caso de los formularios modales en el evento Close, pones algo?, que pasa si hay una excepcion?, el sistema se queda pegado?.

En los formularios mdi basta con la linea que me indicas o hay algo mas?.

Ahora es necesario que al crear los fomularios utilice "nil" en lugar del "self"?


Los formularios modales si te das cuenta en la programacion del boton que lo crea tambien esta el codigo para liberarlos, el FreeAndNil Lo hace todo, en el caso que preguntas si hay una excepcion o el sistema se queda pegado; recuerda que el formulario modal no te dejara operar nada mas mientras este en frente de la aplicacion, la unica excepcion puede ser propiamente en el formulario modal que tienes en frente.

Los MDI, igualmente lo creas y en el onclose lo unico que necesitas es el FreeAndNil, la diferencia es que los mdi los puedes minimizar y trabajar en otro

Saludos

rmora 17-03-2010 18:23:25

Ok, entendido.

Muchas gracias a todos los que colaboraron con el tema, con ello amplie aun mas mis conocimientos.

Muchas Bendiciones....

roman 17-03-2010 18:33:45

Un par de comentarios.

Primero, poner un objeto en nil y luego llamar al método Free no causa ningún problema. Es justamente la virtud de Free, que puede invocarse aún sobre nil. Otra cosa es que en el código propuesto sea innecesario y, de hecho, no es recomendable llamar al destructro de un formulario desde un evento del formulario.

Por otro lado, aun cuando estoy de acuerdo en cuidar el uso de memoria y recursos en general, en mi opinión tampoco hay que exagerar. Crear y destruir cada query sobre la marcha es exagerado. Incluso, si un formulario es usado con frecuencia durante el transcurso de una aplicacíon (por ejemplo, un catálogo de productos) me parece más indicado tenerlo siempre presente y no estarlo creando y destruyendo a cada momento.

// Saludos

dtomeysoto 18-03-2010 15:01:32

Yo uso esto
 
Hola amigos, después de leer este tema les propongo utilizar este fragmento de código luego que hagan el Free.

Código Delphi [-]
procedure Optimizar_memoria;
var
  MainHandle : THandle;
begin
  try
    MainHandle := OpenProcess(PROCESS_ALL_ACCESS, False, GetCurrentProcessID);
    SetProcessWorkingSetSize(MainHandle, DWORD(-1), DWORD(-1));
  finally
    CloseHandle(MainHandle);
  end;
end;

Esto lo encontré en la web tiempo atrás y me ha venido de maravillas. Ahora mismo no recuerdo de dónde lo saqué pero lo he probado y me funciona bien, incluso mirando en el Administrador de tareas la memoria que consume mi aplicación, cuando se ejecuta el código anterior disminuye esta mucho más que después de hacer el Free.

La explicación que daban en la web era que cuando se minimiza una aplicación Windows libera un "pocotón de cosas" y este procedimiento viene a simular algo parecido. Disculpen mi falta de memoria.

Byeeee


La franja horaria es GMT +2. Ahora son las 09:27:32.

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