Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Desarrollo en Delphi para Android
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy


Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 15-01-2015
orihuela orihuela is offline
Registrado
NULL
 
Registrado: ene 2015
Posts: 5
Poder: 0
orihuela Va por buen camino
Gestion de la memoria

Hola a todos, tengo una pregunta tecnica que me gustaria resolver para quedarme tranquilo. Estoy desarrollando una aplicacion en delphi para android y estoy utilizando el patrón arquitectónico "modelo-vista-controlador", aparentemente todo funciona, pero si he notado que cuando la app trabaja mucho la memoria ram del dispostivo se llena (aunque no considerablemente), lo que implica que no se esta liberando bien la memoria y particularmente tengo una duda:

tengo una clase modelo generica que crea un componente tsqlquery en tiempo de ejecucion, el controlador llama al modelo y este devuelve un tsqlquery cargado con la consulta pertinente, a continuacion el controlador delvuelve el tsqlquery al formulario(vista). Os pongo un ejemplo generico:

<<vista>>
type
TForm2 = class(TForm)

procedure FormShow(Sender: TObject);


private
sql:tsqlquery;

public
{ Public declarations }
end;

implementation

procedure TForm1.FormShow(Sender: TObject);
var cliente:tcliente;

begin
cliente:= Tcliente.create;

//esta funccion del controlador cliente carga el tsqlquery con la lista de clientes.
cliente.listarcliente(sql);
// una vez cargado la variable sql se realizan mas operaciones;

end;

< controlador cliente, funcion listar cliente >

procedure TCliente.ListarClientes (var SQL: TSQLQUERY);
var modelocliente: TModeloCliente;


begin

// cuando se ejecuta el contructor del modelo cliente, éste crea un tsqlquery y lo inicializa, el destrucctor de la clase libera dicho tsqlquery.
modelocliente:=TModeloCliente.Create;
// esta funcion devuelve el tsqlquery creado en el contructor y cargado con la consulta.
SQL:= modeloCliente.ListarClientes();
end;


Mi pregunta es, ¿ESTA ASIGNACION SE COPIA POR VALOR O POR REFERENCIA?
SQL:= modeloCliente.ListarClientes();

Lo que si puedo decir es que una vez finalizada la funcion del controlador, el destructor del modelo cliente actua y libera el tsqlquery. Aun así la variable sql del formulario esta correctamente cargada y no esta liberada, lo que me hace pensar que es por copia o que no se esta liberado bien. El problema de la ram puede venir por ahí. cada vez que se crea el modelo se crea un nuevo tsqlquery, ¿se habra liberado el espacio reservado para el anterior?
Responder Con Cita
  #2  
Antiguo 16-01-2015
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.269
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 orihuela Ver Mensaje
Mi pregunta es, ¿ESTA ASIGNACION SE COPIA POR VALOR O POR REFERENCIA?
SQL:= modeloCliente.ListarClientes();

Lo que si puedo decir es que una vez finalizada la funcion del controlador, el destructor del modelo cliente actua y libera el tsqlquery. Aun así la variable sql del formulario esta correctamente cargada y no esta liberada, lo que me hace pensar que es por copia o que no se esta liberado bien. El problema de la ram puede venir por ahí. cada vez que se crea el modelo se crea un nuevo tsqlquery, ¿se habra liberado el espacio reservado para el anterior?
Eso es una asignación de punteros. Al hacerlo SQL debería estar sin crear (apuntando a nil), pues si lo estuviera sí que perderías acceso a la memoria apuntada y por lo tanto tendrías pérdida de memoria.

Al liberar el Query, la variable SQL no se apunta a nil, a no ser que lo hagas manualmente. Si intentas hacer algo con va variable SQL seguramente obtendrás un access Violation, pues esa memoria a la que apunta ya ha sido liberada.
__________________
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
  #3  
Antiguo 16-01-2015
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Esta medio raro tu modelo de datos.

Lo que se ve a simple vista es que tenes una variable llamada "cliente" de tipo TCliente, es decir la variable "cliente" deberia representar solo UNO de los clientes de tu negocio, este deberia conocer su nombre, apellido, mail, y tener metodos como por ej. DeudaPendiente, UltimaCompraRealizada, ProductoMasComprado, etc. Recordar que es UNA instancia de TCLIENTE, siendo TCliente una estructura con metodos y atributos que tienen todos los clientes.

Ahora para modelar comportamiento de varios clientes yo lo que hago es tener otra clase encargada de eso, por ej una TClientMgr o TClientHandler. Esta clase es la que se encarga de "pedirle" a la capa de acceso datos que me traiga la o las instancias de TCliente que necesito. Esta clase por ejmplo conoce metodos como ObtenerCliente(Id: integer): TCliente, ObtenerClientes(<parametros de busqueda>): TList<TCliente> y demases

Es solo una sugerencia para tu codigo, tu pregunta ya la respondio Neftali
Responder Con Cita
  #4  
Antiguo 20-01-2015
orihuela orihuela is offline
Registrado
NULL
 
Registrado: ene 2015
Posts: 5
Poder: 0
orihuela Va por buen camino
Cita:
Empezado por Neftali Ver Mensaje
Eso es una asignación de punteros. Al hacerlo SQL debería estar sin crear (apuntando a nil), pues si lo estuviera sí que perderías acceso a la memoria apuntada y por lo tanto tendrías pérdida de memoria.

Al liberar el Query, la variable SQL no se apunta a nil, a no ser que lo hagas manualmente. Si intentas hacer algo con va variable SQL seguramente obtendrás un access Violation, pues esa memoria a la que apunta ya ha sido liberada.
Eso es lo que en primera instancia yo creia, que es una asigancion de punteros, pero entonces no entiendo algunos comportamientos: sea el siguiente ejemplo:

Código Delphi [-]
  procedure TCliente.ListarClientes (var SQL: TSQLQUERY; filtro: TDictionary<String,String>;orden: TDictionary<String,String>);
var modelocliente: TModeloCliente;
    sqlaux:tsqlquery;


begin
  modelocliente:=TModeloCliente.Create;
  freeandnil(sql);
  SQL:= modeloCliente.ListarClientes(filtro,orden);
  sqlaux:=SQL;
  showmessage(sqlaux.Text);
  freeandnil(sqlaux);
  Showmessage(SQL.Text);
end;

Si realmente es una asigancion de punteros, el ultimo showmessage deberia lanzarme un acess violation puesto que se ha liberado el espacio al que apunta, y para mi sorpresa me muestra el showmessage.
¿Porque?,¿Tal vez sea por como se gestiona la memoria en android?.


De todas maneras así ha quedado el código final, que creo que es lo que te entendí. (Se han añadido las variables reales de la funcion):

<Controlador cliente, Procedimiento ListarClientes >

Código Delphi [-]

procedure TCliente.ListarClientes (var SQL: TSQLQUERY; filtro:  TDictionary<String,String>;orden:  TDictionary<String,String>);
var modelocliente: TModeloCliente;

begin
  
  
  modelocliente:=TModeloCliente.Create;
  // Libero el espacio al que apuntaba anteriomente SQL.
  freeandnil(sql);
  // Se asigna SQL el nuevo Tsqlquery.
  SQL:= modeloCliente.ListarClientes(filtro,orden);

end;




type
  TModeloCliente = class(TModelo) 
  private
  {}
  protected
    { Declaraciones protegidas de la clase }
  public
    function ListarClientes( filtro:TDictionary<String,String>;orden:TDictionary<String,String> ):TSQLQuery;
    function ConsultarCliente( codigo: string ): TSQLQuery;
    function  ObtenerRecargo(codigo:string):string;
    function  ConsultarClientesCompletable(codigo:string): TSQLQuery;
    function  Obtenerrutas():TSQLQuery;
  published
    { Declaraciones publicadas de la clase }
  end;


var cdatos: TSQLConnection;
    QueryGlobal: integer;




type
  TModelo = class(TObject) 
  private
   //esta variable es la que se manda cargada con la consulta pertimente, en listarclientes 
  SQL: TSQLQuery;
  protected
    function DevolverBD():TSQLQuery;
  public
    constructor Create;overload;
    Destructor  Destroy; override;

    procedure EjecutarInstruccion( instruccion:String );
    procedure EjecutarModificacion( instruccion:String );
    function  Genera_Sentencia_Insert(SQL:TDataSet;nombre:String;Campos:Array of String):TStrings;
    function Genera_Sentencia_Update(SQL:TDataSet;nombre,Condicion:String;Campos:Array of String):TStrings;
    procedure EjecutarInsert(nombre:string;Campos:array of string;Valores: Array of variant);
    procedure EjecutarUpdate(nombre,condicion:string;Campos:array of string;Valores: Array of variant);


  published
    { Declaraciones publicadas de la clase }
  end;

< os pongo el codigo del constructor y del destructor, por sí aclara mas la situación >

Código Delphi [-]
 constructor TModelo.Create;
 begin
  inherited;

  if ( cdatos = nil ) then
  begin
  cdatos:=TSQLConnection.Create(Application);
  cdatos.DriverName:='SQLite';
  cdatos.ConnectionName:='cdatos';
  cdatos.Name:='cdatos';
  cdatos.KeepConnection:=True;
  cdatos.LoginPrompt:=False;
  
  cdatos.Params.Add('DriverName=SQLite');
  cdatos.Params.Add('DriverUnit=Data.DbxSqlite');
  cdatos.Params.Add('DriverPackageLoader=TDBXSqliteDriverLoader,DBXSqliteDriver170.bpl');
  cdatos.Params.Add('MetaDataPackageLoader=TDBXSqliteMetaDataCommandFactory,DbxSqliteDriver170.bpl');
  cdatos.Params.Add('FailIfMissing=True');
  cdatos.Params.Add('Database='+TPath.Combine(TPath.GetSharedDocumentsPath, 'Cdatos.s3db'));
  
  cdatos.Connected:=True;
  QueryGlobal:=0;
  end;

  SQL:=TSQLQuery.Create(nil);
  SQL.SQLConnection:=cdatos;
  SQL.Name:='name'+ IntToStr(QueryGlobal);
  QueryGlobal := QueryGlobal + 1;

 end;


destructor TModelo.Destroy;
begin


    //freeandnil(sql);
    
// actualmente la sentecia freeandnill(sql) esta comentada. por lo que  dijistes de que 
//si liberamos esta variable, cuando se destrulla el  modelo, las demas asignaciones que se han 
// hecho de esta variable  deberian fallar, puesto que a lo que apuntan estaria liberado. aunque la practica no lo confirme.

  
  inherited;
end;

No se si me habre explicado bien puesto que el tema no es facil de explicar, pero si necesitas de alguna función mas para su compresión por favor solicitamelo. Un saludo y muchisimas gracias

Última edición por Neftali [Germán.Estévez] fecha: 20-01-2015 a las 18:11:59. Razón: Poner tags al código
Responder Con Cita
  #5  
Antiguo 20-01-2015
orihuela orihuela is offline
Registrado
NULL
 
Registrado: ene 2015
Posts: 5
Poder: 0
orihuela Va por buen camino
Cita:
Empezado por AgustinOrtu Ver Mensaje
Esta medio raro tu modelo de datos.

Lo que se ve a simple vista es que tenes una variable llamada "cliente" de tipo TCliente, es decir la variable "cliente" deberia representar solo UNO de los clientes de tu negocio, este deberia conocer su nombre, apellido, mail, y tener metodos como por ej. DeudaPendiente, UltimaCompraRealizada, ProductoMasComprado, etc. Recordar que es UNA instancia de TCLIENTE, siendo TCliente una estructura con metodos y atributos que tienen todos los clientes.

Ahora para modelar comportamiento de varios clientes yo lo que hago es tener otra clase encargada de eso, por ej una TClientMgr o TClientHandler. Esta clase es la que se encarga de "pedirle" a la capa de acceso datos que me traiga la o las instancias de TCliente que necesito. Esta clase por ejmplo conoce metodos como ObtenerCliente(Id: integer): TCliente, ObtenerClientes(<parametros de busqueda>): TList<TCliente> y demases

Es solo una sugerencia para tu codigo, tu pregunta ya la respondio Neftali
Si, estuve apunto de obtar por el modelo que me dices para la realización del proyecto, pero al final me decidi a trabajar con este modelo, donde el modelo cliente por ejemplo, trata todos los acesos a la bd que tengan que ver con clientes, por tanto una instancia de la tabla cliente de la base de datos representa a un objeto cliente ( que se podria almacenar en una estructura como comentas). Este modelo responde al controlador que le realiza la peticion y este controlador hace de intemediario entre la vista (form) y la capa de datos (modelo);
Lo tendré en cuenta para futuros proyectos, gracias
Responder Con Cita
  #6  
Antiguo 20-01-2015
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.269
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
Por favor, utiliza TAG's cuando escribas código Delphi.
__________________
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
  #7  
Antiguo 20-01-2015
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.269
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 orihuela Ver Mensaje
Si realmente es una asigancion de punteros, el ultimo showmessage deberia lanzarme un acess violation puesto que se ha liberado el espacio al que apunta, y para mi sorpresa me muestra el showmessage.
¿Porque?,¿Tal vez sea por como se gestiona la memoria en android?.
Es posible que sea algo diferente en la gestión o liberación de memoria, porque si creas una estructura similar en Windows, verás que al realizar el último ShowMessage obtienes un "Access Violation"
__________________
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
  #8  
Antiguo 20-01-2015
orihuela orihuela is offline
Registrado
NULL
 
Registrado: ene 2015
Posts: 5
Poder: 0
orihuela Va por buen camino
Smile

Gracias por su atención de momento se va a quedar así, seguire investigando de como puedo bajar la ram. gracias por todo
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

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Gestion de proyectos Angel Vicente Varios 0 15-03-2010 14:37:36
gestion de memoria delphi joni Varios 1 17-03-2005 21:03:36
ISC ERROR CODE:335544344 I/O error for file "c:\gestion\gestion.gdb" eliasterrero Firebird e Interbase 2 28-06-2004 12:20:25
Gestion de Memoria craven Varios 1 04-07-2003 04:31:16
Gestión de Memoria ogorut Varios 2 09-05-2003 17:26:11


La franja horaria es GMT +2. Ahora son las 02:11:25.


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