Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 29-06-2005
ingel ingel is offline
Miembro
 
Registrado: jun 2003
Posts: 239
Poder: 21
ingel Va por buen camino
Liberar componentes de la memoria

Hola ..debo revisar el codigo de un sistema que funciona pero debes en cuando tira errores de acceso a memoria , el clasico FFFFFFFF etc...
asumo que no debe estar liberando correctamente los componentes ,tanto forms , querys , etc..
La pregunta seria ..donde (en que evento) y como liberar eficientemente los componentes de la memoria , ...cuando se sale del from que los usa (onclose? destroy ?), es necesario hacer el close y el free ? sobre todo de las Querys o lo hace solo el delphi ?
Lo mismo con los forms , ya que la creacion se va concatenando..(un form va creando uno o varios y asi sucesivamente) y creo que ahi se descontrola,al ejecutarse varias veces lo mismo ... por ej. en cada boton que llama a otro form hace el Application.CreateForm y el free
si vuelve a presionar el boton hace lo mismo.... estimo que no es lo mejor..no?
saludos
Ingel
Responder Con Cita
  #2  
Antiguo 29-06-2005
Avatar de marcoszorrilla
marcoszorrilla marcoszorrilla is offline
Capo
 
Registrado: may 2003
Ubicación: Cantabria - España
Posts: 11.221
Poder: 10
marcoszorrilla Va por buen camino
En un principio en el OnClose del Formulario pones
Código Delphi [-]
Action:=CaFree;

y no te tiene porque dar problemas.

Un Saludo.
__________________
Guía de Estilo de los Foros
Cita:
- Ça c'est la caisse. Le mouton que tu veux est dedans.
Responder Con Cita
  #3  
Antiguo 29-06-2005
ingel ingel is offline
Miembro
 
Registrado: jun 2003
Posts: 239
Poder: 21
ingel Va por buen camino
y las querys ?

debo hacer el free al salir del form o close o ninguno?

GRACIAS
Responder Con Cita
  #4  
Antiguo 29-06-2005
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.275
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por ingel
..donde (en que evento) y como liberar eficientemente los componentes de la memoria , ...cuando se sale del from que los usa (onclose? destroy ?), es necesario hacer el close y el free ? sobre todo de las Querys o lo hace solo el delphi ?
Los componentes que hay colocados en los formularios no debes liberarlos tú, los liberará el propio formulario cuando lo destruyas. Los que crees tú por código son los que debes destruir tú.
El lugar donde liberarlos depende; La idea es que la visibilidad sea la mínima posible; A parte de eso, el evento OnDestroy es un buen lugar...
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #5  
Antiguo 29-06-2005
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: may 2003
Ubicación: Guatemala
Posts: 6.254
Poder: 27
jachguate Va por buen camino
Cool

Cita:
Empezado por Neftali
Los que crees tú por código son los que debes destruir tú.
Esto no es siempre así. Hay ocasiones en que podes delegar al mecanismo de "propiedad" de los objetos de delphi la liberación de la memoria.

Me explico. Todos aquellos objetos que pueden pertenecer a otro objeto (formalmente los derivados de TComponent) son automáticamente liberados por su propietario (owner) cuando este se destruye.

Así, si creamos un botón de la siguiente forma:

Código Delphi [-]
Var
  b : TButton;

begin
  b := TButton.Create(Form1);
end;

Estableciendo Form1 como su propietario, la memoria del botón será liberada al destruirse form1.

Si a su vez Form1 pertenece al objeto Application, tanto este como el botón serán liberados automáticamente al terminar la aplicación... etc.

Hasta luego.

__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #6  
Antiguo 29-06-2005
ingel ingel is offline
Miembro
 
Registrado: jun 2003
Posts: 239
Poder: 21
ingel Va por buen camino
entonces..

en el proyecto hay una unit con todas las funciones comunes (uUtiles) varias de las cuales crean TQuerys en el var

var QTmp : TQuery;

y luego

QTmp:= TQuery.Create(Application);

para luego conectarse a la DB y consultar o hacer un update por ejemplo..

Estas querys se liberan al liberar el form uUtiles ? (lo que se hace al cerrar la aplicacion) con lo cual se estarian creando cientos de querys sin liberar... o se libera cuando devuelve la llamada que le hizo algun form ?

GRACIAS ..
Responder Con Cita
  #7  
Antiguo 29-06-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por ingel
asumo que no debe estar liberando correctamente los componentes
Yo no creo que ésta sea una suposición correcta. Un objeto esclavo (no liberado) te dará problemas de goteo (memory leack) pero no de ultraje (access violation). Éstos se dan más bien cuando se intenta acceder a objetos ya libres, de manera que yo buscaría el origen del problema en el uso de objetos que posiblemente ya no existan.

// Saludos

pd: traducción de términos con dedicatoria a jachguate
Responder Con Cita
  #8  
Antiguo 29-06-2005
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: may 2003
Ubicación: Guatemala
Posts: 6.254
Poder: 27
jachguate Va por buen camino
Cool

Cita:
Empezado por ingel
Estas querys se liberan al liberar el form uUtiles ? (lo que se hace al cerrar la aplicacion) con lo cual se estarian creando cientos de querys sin liberar... o se libera cuando devuelve la llamada que le hizo algun form ?
Pero... esta decisión no la toma nadie por vos... que sos quien lo decide.

Si no los estas liberando, al ser propiedad de Application, se liberarán hasta le final de la ejecución, cosa que no me parece adecuada para la mayoría de los casos. En todo caso, quien sabe lo que pretende con esto y las necesidades específicas del programa sos vos, o al menos debieras saberlo..

En general es conveniente liberar la memoria tan pronto como el objeto deje de usarse. Así, si una función devuelve un TQuery, lo ideal sería algo como:

Código Delphi [-]
Function UnQuery(Parametros : TipoParametros) : TQuery;
Begin
  result := TQuery.Create(nil);
  result.HagoLoQueTengoQueHacer;
end;

Procedure TForm1.Button1Click(Sender : TObject);

Begin
  with UnQuery(Parametros) do
    try
      ProcesarElQuery;
    finally
      Free; // Libero el query
    end;
end;

//o bien:

Procedure TForm1.Button2Click(Sender : TObject);

Var
  Query : TQuery;

Begin
  Query := UnQuery(Parametros);
  try
    ProcesarElQuery(Query);
  finally
    Query.Free;
  end;
end;

{ si el uso escapa a un procedimiento o función, se puede guardar 
una referencia en el formulario y destruirlo cuando sea conveniente, 
por ejemplo en el evento OnDestroy del formulario }
Type
  TForm1 = class(TForm)
    { Lo generado por delphi }
  private
    FQueryUno : TQuery;
    // otros mienbros, métodos y/o propiedades
  end;

Procedure TForm1.Button3Click(Sender : TObject);

Begin
  if not assigned(FQueryUno) Then
    FQueryUno := UnQuery(Parametros);
  FQueryUno.First; 
  etcetera;
end;

Procedure TForm1.Form1Destroy(Sender : TObject);

Begin
  if assigned(FQueryUno) Then
    FQueryUno.Free;
end;

{ por último, se puede pasar una referencia al objeto que se quiere
  dejar como propietario del query dentro de los parámetros de 
  la función que lo crea, para delegar su destrucción al mecanismo
  de liberación automática de memoria de este objeto }

Procedure TForm1.ButtonYaPerdiLaCuentaClick(Sender : TObject);

Var
  Query : TQuery;

Begin
  Query := UnQuery(Self, OtrosParametros);
  // no hace falta liberar el query, porque self será el owner.
end;


Cita:
Empezado por roman
pd: traducción de términos con dedicatoria a jachguate

¿hay algo malo en mi forma de traducir los términos?
__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #9  
Antiguo 29-06-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por jachguate
¿hay algo malo en mi forma de traducir los términos?
Me refería a esto

-------------------

Normalmente no es buena idea hacer funciones que regresen objetos creados por ellas mismas precisamente porque es difícil dar seguimiento a cuando deben destruirse.

Sin embargo, si esto es absolutamente necesario yo optaría por el uso de interfaces para que la liberación de memoria sea automática.

La idea sería algo así:


Código Delphi [-]
type
  IQueryHolder = interface
    function GetQuery: TQuery;
    property Query: TQuery read GetQuery;
  end;

  TQueryHolder = class(TInterfacedObject, IQueryCreator)
  var
    FQuery: TQuery;

  public
    constructor Create(AQuery: TQuery);
    destructor Destroy; override;

    function GetQuery: TQuery;
  end;

  implementation

  constructor TQueryHolder.Create(AQuery: TQuery);
  begin
    FQuery := AQuery;
  end;

  destructor TQueryHolder.Destroy;
  begin
    FQuery.Free;
    inherited;
  end;

  function TQueryHolder.GetQuery: TQuery;
  begin
    Result := FQuery;
  end;
end.

La interfaz IQueryHolder simplemente mantiene una referencia a un objeto Query. La clase TQueryHolder implementa esta interfaz. Dado que desciende de TInterfacedObject, su destructor será llamado en cuanto se pierda la última referencia a la interfaz y este destructor se encarga de liberar al objeto Query.

Para usar esta interfaz, la función UnQuery descrita por jachguate se debe modificar así:


Código Delphi [-]
function UnQuery(parámetros): IQueryHolder;
var
  Query: TQuery;

begin
  Query := TQuery.Create(nil);
  { pasar parámetros }
  Result := TQueryHolder.Create(Query);
end;

Y para usar el resultado se haría así:


Código Delphi [-]
var
  QueryHolder: IQueryHolder;

begin
  QueryHolder := UnQuery(parámetros);

  QueryHolder.Query.Open;
end;

Como dije antes, Sin importar dónde esté declarada la variable QueryHolder, el objeto Query que contiene se liberará en cuanto se pierda la última referencia.

// Saludos
Responder Con Cita
  #10  
Antiguo 29-06-2005
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.275
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por jachguate
Esto no es siempre así. Hay ocasiones en que podes delegar al mecanismo de "propiedad" de los objetos de delphi la liberación de la memoria.
Así, si creamos un botón de la siguiente forma:

Código Delphi [-]
 Var
   b : TButton;
 
 begin
   b := TButton.Create(Form1);
 end;
Cierto, un pequeño despieste...
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #11  
Antiguo 29-06-2005
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: may 2003
Ubicación: Guatemala
Posts: 6.254
Poder: 27
jachguate Va por buen camino
Cool

Cita:
Empezado por roman
Me refería a esto
Lo siento... no habia captado el asunto... pero efectivamente me convenzo mas cada vez de que algo tenes que ver en la traducción de libros..

Cita:
Empezado por roman
Sin embargo, si esto es absolutamente necesario yo optaría por el uso de interfaces para que la liberación de memoria sea automática.
Es simplemente una idea genial... gracias por compartirla!

Cita:
Empezado por Delphi help (f1)
TInterfacedObject serves as a convenient base class for classes that implement interfaces because it implements the methods of IInterface. TInterfaceObject descendants use the IInterface reference-counting methods to handle lifetime management. That is, when the reference count on a TInterfaceObject descendant drops to zero, the object is automatically freed.
Hasta luego.

__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #12  
Antiguo 29-06-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Los puristas dicen que las interfaces no se hicieron para implementar un recolector de basura. Pero como a mi esto me tiene sin cuidado se puede incluso ir más lejos. En lugar del QueryHolder se hace una interfaz que "publique" los métodos y propiedades principales del objeto Query:


Código Delphi [-]
type
  IQuery = interface
    function ParamByName(const Value: String): TParam;
    function FieldByName(const FieldName: string): TField;

    procedure Open;
    procedure ExecSQL;
  end;

  TQueryObject = class(TInterfacedObject, IQuery)
  private
    FQuery: TQuery;

  public
    constructor Create;
    destructor Destroy; override;

    { IQuery }
    (*
      La clase implementa estas funciones simplemente delegándolas
      a su objeto privado FQuery. Por ejemplo:

      ParamByName --> Result := FQuery.ParamByName(param);
    *)
    function ParamByName(const Value: String): TParam;
    function FieldByName(const FieldName: string): TField;

    procedure Open;
    procedure ExecSQL;
  end;

implementation

constructor TQueryObject.Create;
begin
  FQuery := TQuery.Create;
end;

destructor TQueryObject.Destroy;
begin
  FQuery.Free;
  inherited;
end;

function UnQuery(parámetros): IQuery;
begin
  Result := TQueryObject.Create;
  Result.ParamByName(param).AsXXX := param;
end;

end.

Y se usaría simplemente así:

Código Delphi [-]
var
  Query: IQuery;

begin
  Query := UnQuery(parámetros);
  Query.Open;
end;

De esta manera, el código que use lo devuelto por funciones como UnQuery se ve igual que si se hubiera usado un TQuery directamente.

// Saludos
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 10:58:36.


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
Copyright 1996-2007 Club Delphi