#1121 closed defect (fixed)
Not deleted objects using a TimeSet as argument
Reported by: | Pedro Gea | Owned by: | Víctor de Buen Remiro |
---|---|---|---|
Priority: | high | Milestone: | Mantainance |
Component: | Kernel | Version: | head |
Severity: | major | Keywords: | |
Cc: |
Description
Se encuentran objetos no borrados cuando se utiliza un timeset como argumento de una función.
Véase el siguiente ejemplo que se deja un objeto cada vez:
Real N1 = Copy(NObject); Real { Serie CalIndW(TimeSet dtn) { CalInd(W, dtn) }; Serie CalIndW(C); 0}; Real N2 = Copy(NObject); WriteLn(""<<Real (N2-N1-2));
Change History (12)
comment:1 Changed 14 years ago by
Status: | new → accepted |
---|
comment:2 Changed 14 years ago by
Con respecto al mecanismo de chequeo en TOL de código sospechoso de memory leaks hay una forma de evitar efectos secundarios en el conteo de objetos, que es crear todos los objetos auxiliares al principio y luego modificarlos con :=
de forma que el balance tenga que ser siempre cero:
//Creación de variables Real initial_objects = ?; Real lost_objects = ?; Real aux = ?; //Conteo inicial Real initial_objects := Copy(NObject); Real aux := { //Código de pruebas susceptible de pérdida de objetos 0 }; //Recuento final Real lost_objects := Copy(NObject) - initial_objects; WriteLn("lost_objects = "<< lost_objects );
Otras veces el problema puede aparecer al repetir varias veces cierto código, o por el contrario sólo perderse memoria en la primera iteración y no en las siguientes. Por ello otra forma de chequeo bastante recomendable es la siguiente:
//Creación de variables Real initial_objects = ?; Real lost_objects = ?; Real iter = 1; Real maxIter = 3; //Conteo inicial Real initial_objects := Copy(NObject); //Encapsulación del código Real While(iter<=maxIter, { //Código de pruebas susceptible de pérdida de objetos iter := iter+1 }); //Recuento final Real lost_objects := Copy(NObject) - initial_objects; WriteLn("lost objects = "<< lost_objects+" in "<<maxIter+" iterations" ); WriteLn("lost objects by iteration= "<< (lost_objects/maxIter) );
comment:3 Changed 14 years ago by
Es posible incluso crear una función de chequeo estandarizado
//////////////////////////////////////////////////////////////////////////////// //Chequea si cierto código TOL se deja objetos sin borrar en un ciclo de //longitud dada Real check_memory_leak_in_cycle( Real maxIter, //Número de iteraciones Code code ) //Función de API Real(Real void) con el código sospechoso //////////////////////////////////////////////////////////////////////////////// { //Creación de variables Real initial_objects = ?; Real lost_objects = ?; Real iter = 1; //Conteo inicial Real initial_objects := Copy(NObject); //Encapsulación del código Real While(iter<=maxIter, { //Código de pruebas susceptible de pérdida de objetos Real code(?); iter := iter+1 }); //Recuento final Real lost_objects := Copy(NObject) - initial_objects; WriteLn("lost objects = "<< lost_objects+" in "<<maxIter+" iterations" ); WriteLn("lost objects by iteration= "<< (lost_objects/maxIter) ); lost_objects };
De esta forma podemos constatar fácilmente que no da lo mismo donde se declara el TimeSet de un objeto Serie. En el siguiente código lost.1==3 mientras que lost.2==0 gracias a que el fechado se ha creado en un ámbito superior al de la serie:
Real lost.1 = check_memory_leak_in_cycle(3,Real(Real void) { TimeSet aux = C; Serie CalInd(W, aux); 0 }); Real lost.2 = { TimeSet aux = C; check_memory_leak_in_cycle(3,Real(Real void) { Serie CalInd(W, aux); 0 }) };
comment:4 Changed 14 years ago by
(In [3286]) Refs #1121
Nueva función para el chequeo de agujeros de memoria:
Real CheckMemoryLeakInCycle (Real maxIter, Code code)
Chequea si cierto código TOL se deja objetos sin borrar en un ciclo de longitud dada.
Argumentos:
Real maxIter: Número de iteraciones
Code code: Función de API Real(Real void) con el código sospechoso
Retorna el número de objetos perdidos en el total de iteraciones.
comment:5 Changed 14 years ago by
Vale, ya veo, la cosa es más común de lo que me había parecido al principio.
De hecho parece que la serie no permite que se destruya el timeset de ninguna forma, incluso cuando se nombra o asigna internamente, y es claro que nadie más puede hacer uso de dicho timeset:
Real N1 = Copy(NObject); Real { Serie CalInd(W, D(1)); 0}; Real N2 = Copy(NObject); WriteLn(""<<Real (N2-N1-2)); //> 2
Respecto a lo de usar el nombre del timeset, eso soluciona el problema siempre que el timeset pasado como argumento sea un timeset definido globalmente y no localmente, véase por ejemplo:
Real N1 = Copy(NObject); Real { TimeSet C2 = C; Serie CalIndW(Text dtn) { CalInd(W, Eval(dtn)) }; Serie CalIndW("C2"); 0}; Real N2 = Copy(NObject); WriteLn(""<<Real (N2-N1-2)); //> 1
Y claro, las funciones que se hagan pasando el timeset por nombre dejarán de admitir expresiones del tipo: CalIndW(D(1))
.
comment:6 Changed 14 years ago by
No hace falta que tomes atajos por el momento porque creo que estoy cerca de resolverlo gracias a que han desaparecido otros problemas colaterales que permiten ver mejor lo que está pasando.
comment:8 Changed 14 years ago by
comment:9 Changed 14 years ago by
comment:10 Changed 14 years ago by
comment:11 Changed 14 years ago by
Resolution: | → fixed |
---|---|
Status: | accepted → closed |
No hace falta usar una función para observar el problema, pues este otro código produce el mismo efecto.
Se trata un bug conocido que nunca he podido resolver, y que se debe a que la serie tiene hace uso del TimeSet en el que descansa de una forma que no está controlada por los mecanismos sintácticos. Es decir, el objeto Serie puede sobrevivir al objeto TimeSet en cuyo caso se produciría un acceso de memoria inválido. Por este motivo, se crea una referencia interna desde la Serie al TimeSet que no se destruye hasta que la Serie es destruida. En realidad no es tan sencillo pero más o menos es eso, hay dos mecanismos referenciales que se mezclan y no es fácil hacerlos convivir pacíficamente.
La recomendación es utilizar un texto como argumento de funciones y evaluarlo internamente con
Eval
Como ha habido bastantes mejoras sobre otros memory leaks puede ser un buen momento para reintentar hacer algo de limpieza por ahí.