close Warning: Can't synchronize with repository "(default)" (/var/svn/tolp does not appear to be a Subversion repository.). Look in the Trac log for more information.

Opened 15 years ago

Closed 14 years ago

#880 closed doubt (fixed)

Understanding NObject

Reported by: pgea@… Owned by: Víctor de Buen Remiro
Priority: normal Milestone:
Component: Kernel Version:
Severity: normal Keywords:
Cc:

Description

En el tique #872 se recomendaba usar NObject para comprobar de alguna manera cómo aumenta el número de objetos y poder así controlar que los objetos se destruyen correctamente.

Según he podido ir comprobando el aumento de NObject varía del siguiente modo:

Gramáticas por Valor
Para los objetos de TOL que se asignan por valor, la definición aumenta NObject en 1.
Estas gramáticas son: Complex, Date, Matrix, Polyn, Ratio, Real, Text y VMatrix.

Gramáticas por Referencia
Para los objetos de TOL que se asignan por referencia, la definición aumenta NObject en 1, si el objeto se asigna con uno existente y en 2 si el objeto se asigna con una nueva definición.
Las gramáticas que cumplen esto son: Code, NameBlock y Set.
Al aumento de NObject por la creación de un NameBlock o un Set hay que añadirle el aumento por los objetos contenidos en ellos.
Ejemplos:

Code code1 = ASCII;          //> +1
Real code2 (Real x) { x };   //> +2
Set set01 = Empty;           //> +1
Set set02 = Copy(Empty);     //> +2
Set set03 = [[ Real 1 ]];    //> +3
Set set05 = set04;           //> +1

Gramáticas Especiales
Quedan dos gramáticas que se comportan distinto a las demás: TimeSet y Serie.

TimeSet
Según parece los TimeSet almacenan su definición de modo que cuanto más compleja sea su definición más aumentará NObject.
Por ejemplo:

TimeSet ts01 = C;             //> 1
TimeSet ts02 = D(1);          //> 3
TimeSet ts03 = D(1) * M(1);   //> 6
TimeSet ts04 = Succ(D(2), 1); //> 5
TimeSet ts05 = ts04 * M(1);   //> 4

Aunque no tengo claro como se cuenta esto.

Serie
Los objetos de tipo Serie son quizá los que más me confunden, podemos encontrar incluso que la copia de una serie "ocupa" menos que ella misma:

Real N0 = Copy(NObject);

Serie serie01 = Gaussian(10,1,C);

Real N1 = Copy(NObject);
WriteLn("aumenta "<<(Real N1-N0-1));
//> aumenta 5

Serie serie02 = SubSer(Gaussian(10,1,C),y2009,y2010);

Real N2 = Copy(NObject);
WriteLn("aumenta "<<(Real N2-N1-1));
//> aumenta 8

Serie serie03 = Copy(SubSer(Gaussian(10,1,C),y2009,y2010));

Real N3 = Copy(NObject);
WriteLn("aumenta "<<(Real N3-N2-1));
//> aumenta 3

Change History (5)

comment:1 Changed 15 years ago by Víctor de Buen Remiro

El valor de NObject hay que verlo como un indicador del número de objetos internos realmente creados, lo cual efectivamente no tiene porqué coincidir con el número de objetos visibles desde TOLBase, aunque desde luego si los abarca.

Efectivamente todo lo que has dicho funciona así y no puede ser de otra forma.
Los objetos virtuales puros, TimeSet y series infinitas, sólo pueden almacenarse como un árbol semántico de objetos TOL semejante topológicamente (aunque no siempre exactamente paralelo) al árbol sintáctico con el que se creó.

Veamos un ejemplo, cuando le pides a un TimeSet a = b+(c-d); alguna información, como si tal fecha le pertenece o cual es el sucesor de otra fecha, el objeto a tiene que preguntarle a b y a (c-d) para operar luego la unión (operador +) de las respuestas. Así pues todos los objetos intermedios deben permanecer en memoria dentro de ese árbol durante toda la vida de a.

Cuando copias una serie finita no copia el árbol semántico sino simplemente los datos : fechado, fechas de inicio y fin y vector de valores consecutivos.

No sé si con esto resuelvo estas dudas.

comment:2 Changed 15 years ago by Víctor de Buen Remiro

Resolution: fixed
Status: newclosed

comment:3 Changed 15 years ago by Pedro Gea

Resolution: fixed
Status: closedreopened

Reabro el tique para plantear unas dudas relacionadas con la definición de los objetos con gramática Serie.

Hemos visto que los objetos Serie ocupan un número distinto de objetos (NObject) dependiendo de cómo se definan, siguiendo el ejemplo propuesto anteriormente:

La serie "serie01" ocupa 5 objetos, que podrían entenderse que se encuentran entre los siguientes: el propio objeto Serie, el nombre de la función que los genera y sus argumentos.
Algo similar se supone que ocurre con la serie "serie02" donde los 8 objetos serían los anteriores más la nueva función, sus nuevos argumentos y los datos resultantes.
Sin embargo, la "serie03", que es una copia, ocupa sólo tres.

Esto lleva casi a considerar la existencia de una gramática escondida que representa a las series finitas, que pertenecería al grupo de gramáticas por referencia y que ocuparía tres objetos, uno para la referencia del objeto y otros dos (??) para el objeto Serie en sí mismo:

Serie serie04 = serie03;

Real N4 = Copy(NObject);
WriteLn("aumenta "<<(Real N4-N3-1));
//> aumenta 2

Ante esto me pregunto:

  • No sería (o hubiera sido) conveniente hacer una diferencia explícita entre estas gramáticas del mismo modo que se diferencian Matrix y VMatrix.
  • Aunque el número de objetos sea simplemente una medida muy superficial del número de objetos, entiendo que la copia de la serie ("serie02") ocupa menos en memoria que la serie en sí misma ("serie03").

Pues debemos tener en cuenta que "serie02" al ser una pseudo-"serie finita", ya almacena dentro de sí los valores aleatorios calculados junto a la definición que ya no sirve para nada, ¿no?.

  • Simplemente por motivos de aprovechamiento de los recursos, ¿no deberíamos hacer siempre un SubSer con un Copy?: Copy(SubSer(...)) .

comment:4 Changed 15 years ago by Víctor de Buen Remiro

No tiene mucho sentido hablar de lo que podría haber sido y no fue. Lo que hay es lo que podía haber sin más. Las razones son siempre las mismas el lenguaje evoluciona según las necesidades de cada momento y guardando el máximo nivel de compatibilidad hacia atrás lo cual impide actuar de la forma más congruente.

No hay ninguna diferencia sintáctica relevante entre las series finitas e infinitas por lo que no tiene sentido que haya dos tipos de datos.

Tampoco la hay entre Matrix y VMatrix, y o ideal hubiera sido que Matrix hubiera crecido desde dentro hasta ser lo que ahora es VMatrix pero no había ninguna forma de hacer eso con compatibilidad hacia atrás y continuidad.

Con respecto al contador de objetos hace lo que puede hacer que es contar las veces que se pasa por los constructores de BSyntaxObject y restarle las que se pasa por el destructor. Cualquier otra cosa es inviable. El uso de NObject es la detección de memory-leaks de alto nivel, por lo que el valor concreto que toma es irrelevante: sólo importa si crece tras un ciclo en el que debería permanecer constante.

Las copias de objetos de tipo Serie, sean finitas o no, son internamente una mera referencia, así que no añaden apenas overhead, pero lo qe no pueden hacer es ahorrar nada por el hecho de existir.

Yo sí recomiendo hacer SubSer en todo lo que no sean objetos globales de interés general. Es decir, una serie como

  Serie   DiasDelMes       = CalVar(C,     Mensual);

de la StdLib debe ser infinita para que cualquiera la pueda usar en el intervalo que le interese, pero una vez conocido el intervalo en el que se va a usar lo mejor es crearse su propia instancia acotada con SubSer.

Lo que sobra es el Copy que no aporta nada en esotos casos.

comment:5 Changed 14 years ago by Víctor de Buen Remiro

Resolution: fixed
Status: reopenedclosed
Note: See TracTickets for help on using tickets.