Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Error de Memoria Super Raro (https://www.clubdelphi.com/foros/showthread.php?t=91108)

rmendoza83 12-11-2016 19:13:17

Error de Memoria Super Raro
 
2 Archivos Adjunto(s)
Buenas Tardes muchachos, un saludo cordial.

Les escribo buscando algo de luz a un problemita que me esta sucediendo en el proyecto que trabajamos actualmente. espero poder dar una explicación para que la ayuda sea mas conforme.

Mi aplicacion basicamente es un sistema administrativo, funciona bajo un modelo cliente servidor, hago uso de componentes zeos y la base de datos principal es postgresql 9.5, todo esto esta muy chevere, viene la parte complicada, los formularios que hago uso tengo varias plantillas dependiendo del tipo de formulario (formularios independientes, formularios maestro/detalle, formularios dependientes, etc), basicamente son formularios bases y mediante herencia creo los nuevos lo que me permite escribir menos codigo.

El problema lo estoy teniendo en un formulario de cotización o presupuesto, técnicamente el formulario funciona bien y hace todas sus operaciones bien, dado que es una vulgar copia del formulario de facturacion de clientes (con algunas pequeñas diferencias), pero me esta pasando que cuando abro dicho formulario (presupuesto) hago uso de el, agrego registros consulto, imprimo reportes etc etc etc todo muy bien, pero cuando cierro mi aplicación me manda un error de acceso a memoria (EAccessViolation), todos los demás formularios similares (facturación clientes, pedidos clientes, anticipos clientes, etc etc) funcionan muy bien sin este error, y el error solo me ocurre cuando por alguna razón abro el formulario, mientras no lo abro y cierro mi aplicacion todo OK.

Les adjunto par de imagenes de los formularios para que tengan una idea de los componentes usados y el codigo de ambas para ver si ven algo en particular que yo no estoy viendo.

Espero no confundirlos mucho, cabe destacar que mi aplicacion crea los formularios dinamicamente, y basicamente se crean de la manera como lo hace Application.CreateForm(Form,TFORM), asi que no hay ningun secreto en especial de como crear los formularios. Les doy las gracias de antemano por cualquier idea que me puedan dar.

Saludos.

AgustinOrtu 12-11-2016 20:00:08

Los Access Violations no son muchas las posibilidades:

Código Delphi [-]
procedure Foo;
var
  bla: TAlgunaClase;
begin
  // el objeto no fue inicializado.. en realidad en estos casos puede pasar "cualquier cosa"
  // ya que bla es un puntero a alguna zona de memoria que vaya uno a saber que tiene
  bla.AlgunMetodo; // EAccesViolation es lo mas "normal"

  bla := TAlgunaClase.Create;
  bla.AlgunMetodo; // todo bien
  bla.Free;
  bla.AlgunMetodo; // EAccesViolation, porque se libero la memoria a la que apuntaba bla

  bla := nil;
  bla.AlgunMetodo; // EAccesViolation
end;

El depurador no te lleva a la linea que produce la excepcion? la forma mas sencilla de rastrearlo es con un depurador. Revisa los destructores. Revisa el codigo que no acceda a cosas que no fueron creadas/hayan sido liberada de memoria. Pon puntos de ruptura y sigue paso a paso. Mira hasta donde llega el programa y donde se rompe

AgustinOrtu 12-11-2016 20:06:52

Para aportar mas al hilo:

Código Delphi [-]
program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  TAlgunaClase = class
  public
    procedure MetodoNormal;
    procedure MetodoVirtual; virtual;
    procedure MetodoConstante;
    procedure MetodoConstanteVirtual; virtual;
  end;

procedure TAlgunaClase.MetodoConstante;
begin
  Writeln('Metodo Constante: Hola mundo');
end;

procedure TAlgunaClase.MetodoConstanteVirtual;
begin
  Writeln('MetodoConstanteVirtual: Hola mundo virtual');
end;

procedure TAlgunaClase.MetodoNormal;
begin
  Writeln('MetodoNormal: ' + QualifiedClassName);
end;

procedure TAlgunaClase.MetodoVirtual;
begin
  Writeln('MetodoVirtual: ' + QualifiedClassName);
end;

var
  Foo: TAlgunaClase;
begin
  try
    try
      Foo.MetodoNormal; // EAccessViolation
    except
      Writeln('Fallo Foo.MetodoNormal')
    end;

    try
      Foo.MetodoVirtual; // EAccessViolation
    except
      Writeln('Fallo Foo.MetodoVirtual')
    end;

    try
      Foo.MetodoConstante; // este no falla
    except
      Writeln('Fallo Foo.MetodoConstante')
    end;

    try
      Foo.MetodoConstanteVirtual; // EAccessViolation
    except
      Writeln('Fallo Foo.MetodoConstanteVirtual')
    end;
  finally
    Readln;
  end;
end.

Interesante que invocar a un metodo constante sobre una instancia nil o con basura no eleve una excepcion. Con metodo constante me refiero a que no utiliza informacion interna del objeto como en el ejemplo

AgustinOrtu 12-11-2016 20:25:50

Y este es el caso mas oscuro de todos :D

Código Delphi [-]
var
  Foo: TAlgunaClase;
begin
  Foo := TAlgunaClase.Create;
  Foo.Free;
  try
    Foo.MetodoNormal;
    Foo.MetodoVirtual;
    Foo.MetodoConstante;
    Foo.MetodoConstanteVirtual;
  finally
    Readln;
  end;
end.

Salida:

Código:

MetodoNormal: Project1.TAlgunaClase
MetodoVirtual: Project1.TAlgunaClase
Metodo Constante: Hola mundo
MetodoConstanteVirtual: Hola mundo virtual


jhonny 12-11-2016 21:59:39

Cita:

Empezado por AgustinOrtu (Mensaje 510690)
Y este es el caso mas oscuro de todos :D

Código Delphi [-]
var
  Foo: TAlgunaClase;
begin
  Foo := TAlgunaClase.Create;
  Foo.Free;
  try
    Foo.MetodoNormal;
    Foo.MetodoVirtual;
    Foo.MetodoConstante;
    Foo.MetodoConstanteVirtual;
  finally
    Readln;
  end;
end.

Salida:

Código:

MetodoNormal: Project1.TAlgunaClase
MetodoVirtual: Project1.TAlgunaClase
Metodo Constante: Hola mundo
MetodoConstanteVirtual: Hola mundo virtual



jejeje caramba, no me imaginé que esto sucediera, ya estaba sorprendido con el primer caso donde MetodoConstante funcionaba y ahora esto... vaya oscuridad :eek:

dec 12-11-2016 22:21:13

Hola a todos,

Interesante cuanto menos... :)

rmendoza83 13-11-2016 02:23:58

Cita:

Empezado por AgustinOrtu (Mensaje 510688)
Los Access Violations no son muchas las posibilidades:

Código Delphi [-]
procedure Foo;
var
  bla: TAlgunaClase;
begin
  // el objeto no fue inicializado.. en realidad en estos casos puede pasar "cualquier cosa"
  // ya que bla es un puntero a alguna zona de memoria que vaya uno a saber que tiene
  bla.AlgunMetodo; // EAccesViolation es lo mas "normal"

  bla := TAlgunaClase.Create;
  bla.AlgunMetodo; // todo bien
  bla.Free;
  bla.AlgunMetodo; // EAccesViolation, porque se libero la memoria a la que apuntaba bla

  bla := nil;
  bla.AlgunMetodo; // EAccesViolation
end;

El depurador no te lleva a la linea que produce la excepcion? la forma mas sencilla de rastrearlo es con un depurador. Revisa los destructores. Revisa el codigo que no acceda a cosas que no fueron creadas/hayan sido liberada de memoria. Pon puntos de ruptura y sigue paso a paso. Mira hasta donde llega el programa y donde se rompe


Gracias por la respuesta! Realmente es lo que hago! pero no encuentro el problema! pero es como digo que el codigo funciona bien en otros modulos pero ese en particular no! le echaste un ojo a los codigos? muy complejos?

AgustinOrtu 14-11-2016 18:54:18

Simplemente a ojo es imposible depurarlo. Debes ir paso a paso y usar el depurador de Delphi! El mismo te dice en que linea ocurren los errores, y podes ir instruccion por instruccion siguiendo la ejecucion.

Yo probaria poner puntos de ruptura en los eventos de los controles, a ver si cuando cierras el form se dispara alguno (por ejemplo algunos de los OnExit) y hace uso de memoria no asignada


La franja horaria es GMT +2. Ahora son las 01:49:14.

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