]> git.llucax.com Git - z.facultad/75.00/informe.git/commitdiff
Empezar con el capítulo de GC
authorLeandro Lucarella <llucax@gmail.com>
Sat, 23 May 2009 02:28:20 +0000 (23:28 -0300)
committerLeandro Lucarella <llucax@gmail.com>
Sat, 23 May 2009 03:44:31 +0000 (00:44 -0300)
Está terminada toda la introducción y bastante avanzado hasta el
conteo de referencias.

source/gc.rst
source/referencias.rst

index 00cee40b8c282fa7b2a52ad1d8c4751cc8af115a..100614f6c537ddc5df723237110ee4bd50e5aea5 100644 (file)
 Recolección de basura
 ============================================================================
 
-TODO
 
-.. Breve descripción de la utilidad de la recolección de basura
-   ESTADO: TERMINADO
-
-La recolección de basura es muchas veces vista por sus críticos de
-una forma bastante *naïve*. Muchas veces se argumenta que sólo es
-útil para programadores descuidados o que su necesidad es sólo una
-manifestación de un mal diseño. Si bien estas dos afirmaciones pueden
-ser, en algunos casos, ciertas, es falaz pensar que ese es la única
-ventaja de un recolector de basura. Uno de los aspectos más importantes
-de un recolector de basura es lograr un mayor nivel de abstracción
-[JOLI96]_. En particular, al diseñar o programar bibliotecas, de no
-haber un recolector de basura, **la administración de memoria pasa a ser
-parte de la interfaz de la biblioteca**. Y lo peor de este aspecto es
-que muy pocas veces esto es tenido en cuenta, derivando en bibliotecas
-muy difíciles de usar correctamente sin perder memoria, por no quedar
-bien clara la responsabilidad del manejo de memoria.
-
-Esto se debe a que, como se mencionó anteriormente, el manejo de memoria
-es un *artefacto* proveniente del *hardware*, no un concepto propio
-de los algoritmos a representar y como tal, nos impide desarrollar una
-mayor abstracción.
-
-Muchas veces se aduce también que la recolección de basura impide
-el desarrollo de programas eficientes. Si bien es innegable que la
-recolección de basura impone una carga extra, ésta es, en la mayoría
-de los casos, imperceptible. Incluso algunos algoritmos de recolección
-de basura pueden aumentar la eficiencia en casos determinados, como los
-recolectores que compactan, que pueden minimizar considerablemente la
-cantidad de páginas de memoria referenciadas por el programa, mejorando
-el *hit-ratio* tanto de la memoria virtual como del *cache*.  Aún si
-este no fuera el caso, o en casos de sistemas de tiempo real o zonas muy
-críticas en cuanto a la eficiencia, muchas veces es posible suspender
-el recolector de basura en dicho fragmento de código. Es cierto que esto
-rompe un poco con la idea de ganar abstracción, pero es necesario sólo
-en casos donde hay que realizar optimizaciones y las optimizaciones son,
-en general, dependientes de la plataforma (*hardware*) y por lo tanto
-de difícil abstracción.
+Introducción
+----------------------------------------------------------------------------
+
+*Recolección de basura* se refiere a la recuperación automática de memoria
+del *heap* [#gcheap]_ una vez que el programa ha dejado de hacer referencia
+a ella (y por lo tanto, ha dejado de utilizarla).
+
+A medida que el tiempo pasa, cada vez los programas son más complejos y es
+más compleja la administración de memoria. Uno de los aspectos más
+importantes de un recolector de basura es lograr un mayor nivel de
+abstracción y modularidad, dos conceptos claves en la ingeniería de
+software [JOLI96]_. En particular, al diseñar o programar bibliotecas, de
+no haber un recolector de basura, **la administración de memoria pasa a ser
+parte de la interfaz**, lo que produce que los módulos tengan un mayor
+grado de acoplamiento.
+
+Además hay una incontable cantidad de problemas asociados al manejo
+explícito de memoria que simplemente dejan de existir al utilizar un
+recolector de basura. Por ejemplo, los errores en el manejo de memoria
+(como *buffer overflows* [#gcbuff]_ o *dangling pointers* [#gcdang]_) son
+la causa más frecuente de problemas de seguridad [BEZO06]_.
+
+La recolección de basura nació junto a Lisp_ a finales de 1950 y en los
+siguientes años estuvo asociada principalmente a lenguajes funcionales,
+pero en la actualidad está presente en prácticamente todos los lenguajes de
+programación, de alto o bajo nivel, aunque sea de forma opcional. En los
+últimos 10 años tuvo un gran avance, por la adopción en lenguajes de
+desarrollo rápido utilizados mucho en el sector empresarial, en especial
+Java_, que fue una plataforma de facto para la investigación y desarrollo
+de recolectores de basura (aunque no se limitaron a este lenguaje las
+investigaciones).
+
+En las primeras implementaciones de recolectores de basura la penalización
+en la eficiencia del programa se volvía prohibitiva para muchas
+aplicaciones. Es por esto que hubo bastante resistencia a la utilización de
+recolectores de basura, pero el avance en la investigación fue haciendo que
+cada vez sea una alternativa más viable al manejo manual de memoria,
+incluso para apliaciones con altos requerimientos de eficiencia. En la
+actualidad un programa que utiliza un recolector moderno puede ser
+comparable en eficiencia con uno que utiliza un esquema manual. En
+particular, si el programa fue diseñado con el recolector de basura en
+mente en ciertas circunstancias puede ser incluso más eficiente que uno que
+hace manejo explícito de la memoria. Muchos recolectores mejoran la
+localidad de referencia, haciendo que el programa tenga un mejor
+comportamiento con el caché y la memoria virtual.
 
 El recolector de basura debe tener un comportamiento correcto y predecible
 para que sea útil, si el programador no puede confiar en el recolector
@@ -57,60 +64,1302 @@ introduce nuevos puntos de falla en los programas, y lo que es peor,
 puntos de falla no controlados por el programador, volviendo mucho más
 difícil la búsqueda de errores.
 
-.. Presenta el problema y temas a ser tratados en el trabajo.
-   ESTADO: TERMINADO
-
-Los lenguajes de programación modernos tienen una tendencia cada vez
-más marcada a adoptar técnicas sofisticadas, haciéndolos más ricos y
-convirtiéndolos realmente en lenguajes, no en meros preprocesadores que
-convierten de una forma muy directa el código en *assembly*, permitiendo
-construcciones semánticamente más ricas y permitiendo al programar una
-mayor expresividad para plasmar algoritmos sin detenerse en los detalles
-del *hardware*.
-
-Estos conceptos supuestamente avanzados provienen, en general, de
-lenguajes académicos (muchos de ellos funcionales) que implementan estas
-funcionalidades hace mucho tiempo, pero que para su época, o bien no
-tuvieron suficiente difusión en el ambiente comercial, o bien eran muy
-lentos por la baja capacidad de procesamiento de la época o incluso
-demasiado *revolucionarios* para ser adoptados por programadores que no
-podían ver las ventajas que esos nuevos conceptos proveen.
-
-El caso de la recolección de basura (*garbage collection* en inglés)
-es uno de los más representativos. Lisp_ introdujo a principio de los
-'60 este concepto, como un mecanismo para alocar y liberar recursos
-(en general memoria alocada en el *heap*) de forma automática. Pero
-no fue hasta avanzados los '90 que esta técnica se empezó a utilizar
-en lenguajes de programación de uso comercial, cuando fue popularizado
-por Java_. Incluso luego de más de 30 años para Java_ era costosa la
-recolección de basura, lo que sumado a la presencia de una máquina
-virtual para ejecutar los programas producidos, condujo a que estos
-lenguajes sean notablemente lentos. Aún así Java_ creció y entre las
-mejoras introducidas hubieron mejoras en la recolección de basura. Otros
-lenguaje de programación populares que utilizan alguna forma de
-recolección de basura son Python_, Ruby_, PHP_ y `C#`_, entre otros.
 
+.. [#gcheap] *Heap* es un área de memoria que se caracteriza por ser
+   dinámica (a diferencia del área de memoria estática que está disponible
+   durante toda la ejecución de un programa). Un programa puede reservar
+   memoria en tiempo de ejecución según sea necesario y liberarla cuando ya
+   no la necesita. A diferencia del *stack*, la duración de la *reserva* no
+   está atada a un bloque de código.
+.. [#gcbuff] Un *buffer overflow* (*desbordamiento de memoria* en
+   castellano) se produce cuando se copia un dato a un área de memoria que
+   no es lo suficientemente grande para contenerlo. Esto puede producir que
+   el programa sea abortado por una violación de segmento, o peor,
+   sobreescribir un área de memoria válida, en cuyo caso los resultados son
+   impredecibles.
+.. [#gcdang] Un *dangling pointer* (*puntero colgante* en castellano) es un
+   puntero que apunta a un área de memoria inválida. Ya sea porque el
+   elemento apuntado no es el mismo tipo o porque la memoria ya ha sido
+   liberada. Al ser desreferenciado, los resultados son impredecibles, el
+   programa podría abortarse por una violación de segmento o podrían pasar
+   peores cosas si el área de memoria fue realocada para almacenar otro
+   objeto.
 
 
-Introducción
-----------------------------------------------------------------------------
 
-TODO
+Conceptos básicos
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Los programas pueden hacer uso principalmente de 4 áreas de memoria:
+
+Registros:
+   Se trata de la memoria más básica de una computadora. Es el área de
+   memoria en la que puede operar realmente el procesador, es extremadamente
+   escasa y generalmente su uso es administrado por el lenguaje de
+   programación (o compilador más específicamente). Excepto en situaciones
+   muy particulares, realizando tareas de muy bajo nivel, un programador
+   nunca manipula los registros explícitamente.
+
+Área de memoria estática:
+   Es la forma de memoria más simple que un programador utiliza
+   explícitamente. En general las variables globales se almacenan en este
+   área, que es parte inherente del programa y está disponible durante toda
+   su ejecución, por lo tanto nunca cambia su capacidad en tiempo de
+   ejecución. Es la forma más básica de administrar memoria, pero tiene una
+   limitación fundamental: **el tamaño de la memoria tiene que ser conocido
+   en tiempo de compilación**. Los primeros lenguajes de programación solo
+   contaban con este tipo de memoria (además de los registros del
+   procesador).
+
+*Stack* (pila):
+   Los primeros lenguajes de programación que hicieron uso de una pila
+   aparecieron en el año 1958 (Algol-58 y Atlas Autocode) y fueron los
+   primeros en introducir estructura de bloques, almacenando las
+   variables locales a estos bloques utilizando una pila [JOLI96]_.
+   Esto permite utilizar recursividad y tener un esquema simple de memoria
+   dinámica. Sin embargo este esquema es muy limitado porque el orden de
+   reserva y liberación de memoria tiene que estar bien establecido. Una
+   celda [#gccelda]_ alocada antes que otra nunca puede ser liberada antes
+   que aquella.
+
+*Heap*:
+   A diferencia del *stack*, el *heap* provee un área de memoria que puede
+   ser obtenida dinámicamente pero sin limitaciones de orden. Es el tipo de
+   memoria más flexible y por lo tanto el más complejo de administrar; razón
+   por la cual existen los recolectores de basura.
+
+La recolección de basura impone algunas restricciones sobre la manera de
+utilizar el *heap*. Debido a que un recolector de basura debe ser capaz de
+determinar el grafo de conectividad de la memoria en uso, es necesario que
+el programa siempre tenga alguna referencia a las celdas activas en los
+registros, memoria estática o *stack* (normalmente denominado *root set*).
+
+Esto implica que una celda sea considerada basura si y sólo si no puede ser
+alcanzada a través del grafo de conectividad que se comienza a recorrer
+desde el *root set*. Por lo tanto, una celda está *viva* si y sólo si su
+dirección de memoria está almacenada en una celda *raíz* (parte del *root
+set*) o si está almacenada en otra celda *viva* del *heap*.
+
+Expresado más formalmente, dada la relación :math:`M \to N`, donde
+:math:`M` es una celda del *heap* o parte del *root set* y :math:`N` es una
+celda del *heap*, definida como:
+
+.. math::
+
+   M \to N \Longleftrightarrow M \text{ almacena un puntero a } N
+
+El conjunto de celdas vivas (o *live set*) queda determinado por:
+
+.. math::
+
+   vivas = \left\lbrace N \in Celdas \big/
+      ( \exists r \in Raices / r \to N ) \vee (\exists M \in vivas / M \to N )
+   \right\rbrace
+
+Cabe aclarar que esta es una definición conceptual, asumiendo que el
+programa siempre limpia una dirección de memoria almacenada en el *root
+set* o una celda del *heap* cuando la celda a la que apunta no va a ser
+utilizada nuevamente. Esto no es siempre cierto y los falsos positivos que
+esto produce se conoce como un tipo de pérdida de memoria (que es posible
+incluso al utilizar un recolector de basura) llamada pérdida de memoria
+*lógica*. Esto puede no ser evitable (incluso cuando el programador no
+cometa errores) en lenguajes de programación que requieran un recolector de
+basura conservativo.
+
+Por último, siendo que el recolector de basura es parte del programa de
+forma indirecta, es común ver en la literatura que se direfencia entre
+2 partes del programa, el recolector de basura y el programa en sí. Dado
+que para el recolector de basura, lo único que interesa conocer del
+programa en sí son los cambios al grafo de conectividad de las celdas,
+normalmente se lo llama *mutator* (mutador).
+
+
+.. [#gccelda] En general en la literatura se nombra a una porción de
+   memoria alocada individualmente *celda*, *nodo* u *objeto*
+   indistintamente. En este trabajo se utilizará la misma nomenclatura
+   (haciendo mención explícita cuando alguno de estos términos se refiera
+   a otra cosa, como al nodo de una lista o a un objeto en el sentido de
+   programación orientada a objetos).
+
+
+
+Recorrido del grafo de conectividad
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+El problema de encontrar las celdas *vivas* de un programa se reduce a recorrer
+un grafo dirigido. El grafo se define como:
+
+.. math::
+
+   G = (V,A)
+
+Donde :math:`V` es el conjunto de vértices, dado por las celdas de memoria
+y :math:`A` es un conjunto de pares ordenados (aristas), dado por la
+relación :math:`M \rightarrow N` (es decir, los punteros).
+
+El grafo comienza a recorrerse desde el *root set* y todos los vértices que
+fueron visitados componen el *live set*; el resto de los vértices son
+*basura*.
+
+Más formalmente, Definimos:
+
+*Camino*:
+   secuencia de vértices tal que cada uno de los vértices tiene una arista
+   al próximo vértice en la secuencia. Todo camino finito tiene un *vértice
+   inicial* y un *vértice final* (llamados en conjunto *vértices
+   terminales*). Cualquier vértice no terminal es denominado *vértice
+   interior*.
+
+   .. math::
+
+      \underset{v_1 \rightarrow v_N}{C} = \left\lbrace
+         v_1, \dotsc, v_N \in V \big/ \underset{i \in [1,N-1]}{\forall v_i}
+            \exists (v_i \to v_{i+1}) \in A
+      \right\rbrace
+
+*Conexión*:
+   decimos que :math:`M` está *conectado* a :math:`N` si y sólo si existe un
+   camino de :math:`M` a :math:`N`.
+
+   .. math::
+
+      M \mapsto N \Longleftrightarrow \exists \underset{M \to N}{C} \in G
+
+*Live set*:
+   el conjunto de celdas *vivas* está dado por todos los vértices
+   (:math:`v`) del grafo para los cuales existe una raíz en el *root set*
+   que esté conectada a él.
+
+   .. math::
+
+      Live \thickspace set = \left\lbrace v \in V \big/
+         \left( \exists r \in Root \thickspace set \big/ r \mapsto v \right)
+      \right\rbrace
+
+*Basura*:
+   la basura, o celdas *muertas*, quedan determinadas entonces por todas las
+   celdas del *heap* que no son parte del *live set*.
+
+   .. math::
+
+      Basura = V - Live \thickspace set
+
+Esto es, efectivamente, una partición del *heap*.
+
+.. TODO: figure
+
+.. raw:: latex
+
+   \begin{figure}[htp] \centering
+
+.. digraph:: g1
+
+   margin  = 0;
+   ratio   = fill;
+   size    = "4.6,3.6";
+   node [ shape = record, width = 0, height = 0 ];
+
+   subgraph cluster_heap {
+      label = "Heap";
+      style     = dashed;
+      color     = gray40;
+      fontcolor = gray40;
+
+      subgraph cluster_live {
+         label     = "Live set";
+         style     = dashed;
+         color     = gray40;
+         fontcolor = gray40;
+         node [
+            style     = filled,
+            fillcolor = gray25,
+            fontcolor = white,
+         ];
+         h1; h2; h4; h5; h6;
+      }
+
+      subgraph cluster_garbage {
+         label     = "Basura";
+         style     = dashed;
+         color     = gray40;
+         fontcolor = gray40;
+         node [ style = filled, fillcolor = white ];
+         h7; h3;
+      }
+   }
+
+   subgraph cluster_root {
+      label     = "Root set";
+      style     = dashed;
+      color     = gray40;
+      fontcolor = gray40;
+      node [ style = filled, fillcolor = gray96 ];
+      r0; r1; r2;
+   }
+
+   r0 -> h1 -> h2 -> h5;
+   r1 -> h5 -> h6 -> h1;
+   r2 -> h4;
+   h5 -> h4;
+   h7 -> h1;
+   h7 -> h3;
+
+.. raw:: latex
+
+   \caption{Distintas partes de la memoria, incluyendo relación entre
+   basura, live set, heap y root set.}
+   \end{figure}
+
+Al proceso de visitar los vértices *conectados* desde el *root set* se lo
+denomina *marcado*, *fase de marcado* o *mark phase* en inglés, debido
+a que es necesario marcar los vértices para evitar visitar 2 veces el mismo
+nodo en casos de que el grafo contenga ciclos [#gccycle]_. De forma similar
+a la búsqueda, que puede realizarse *primero a lo ancho* (*breadth-first*)
+o *primero a lo alto* (*depth-first*) del grafo, el marcado de un grafo
+también puede realizarse de ambas maneras. Cada una podrá o no tener
+efectos en la eficiencia, en particular dependiendo de la aplicación puede
+convenir uno u otro método para lograr una mejor localidad de referencia
+y de esta manera tener un mejor comportamiento de la memoria virtual o del
+*caché*.
+
+Un algoritmo simple (recursivo) de marcado *primero a lo alto*  puede ser
+el siguiente (asumiendo que partimos con todos los vértices sin marcar)
+[#gcpseudo]_::
+
+   mark(v)
+      if not v.marked
+         v.marked = true
+         for (src, dst) in v.edges
+            mark(dst)
+
+   mark_phase()
+      for r in root_set
+         mark(r)
+
+Una vez concluido el marcado, sabemos que todos los vértices con la marca
+son parte del *live set* y que todos los vértices no marcados son *basura*.
+Esto es conocido también como **abstracción bicolor**, dado que en la
+literatura se habla muchas veces de *colorear* las celdas. En general, una
+celda sin marcar es de color blanco y una marcada de color negro.
+
+.. TODO: figure
+
+.. raw:: latex
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO texto más largo y más largo y larguísimo porque tiene
+   muchas cosas que decir]{
+
+.. digraph:: g2_1
+
+   margin = 0;
+   ratio  = fill;
+   size   = "2.0,2.6";
+   node [ shape = record, width = 0, height = 0];
+   edge [ color = gray40 ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+      ];
+
+      subgraph marked {
+         node [ style = filled, fillcolor = gray25, fontcolor = white ];
+         h1;
+      };
+
+      root:r0 -> h1 [ style = bold, color = black ];
+      h1 -> h2 -> h5 -> h1;
+      root:r1 -> h6 -> h2;
+      h4 -> h3;
+      h3 -> h5;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g2_2
 
+   margin = 0;
+   ratio  = fill;
+   size   = "2.0,2.6";
+   node [ shape = record, width = 0, height = 0 ];
+   edge [ color = gray40 ];
 
+   subgraph cluster_all {
 
-Algoritmos principales
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+      ];
+
+      subgraph marked {
+         node [ style = filled, fillcolor = gray25, fontcolor = white ];
+         h1; h2;
+      };
+
+      root:r0 -> h1 [ color = gray10 ];
+      h1 -> h2 [ style = bold, color = black ];
+      h2 -> h5 -> h1;
+      root:r1 -> h6 -> h2;
+      h4 -> h3;
+      h3 -> h5;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g2_3
+
+   margin = 0;
+   ratio  = fill;
+   size   = "2.0,2.6";
+   node [ shape = record, width = 0, height = 0 ];
+   edge [ color = gray40 ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+      ];
+
+      subgraph marked {
+         node [ style = filled, fillcolor = gray25, fontcolor = white ];
+         h1; h2; h5;
+      };
+
+      root:r0 -> h1 [ color = gray10 ];
+      h1 -> h2 [ color = gray10 ];
+      h2 -> h5 [ style = bold, color = black ];
+      h5 -> h1;
+      root:r1 -> h6 -> h2;
+      h4 -> h3;
+      h3 -> h5;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, part 1}
+   \end{figure}
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO]{
+
+.. digraph:: g2_4
+
+   margin = 0;
+   ratio  = fill;
+   size   = "2.0,2.6";
+   node [ shape = record, width = 0, height = 0 ];
+   edge [ color = gray40 ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+      ];
+
+      subgraph marked {
+         node [ style = filled, fillcolor = gray25, fontcolor = white ];
+         h1; h2; h5;
+      };
+
+      root:r0 -> h1 [ color = gray10 ];
+      h1 -> h2 [ color = gray10 ];
+      h2 -> h5 [ color = gray10 ];
+      h5 -> h1 [ style = bold, color = black ];
+      root:r1 -> h6 -> h2;
+      h4 -> h3;
+      h3 -> h5;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g2_5
+
+   margin = 0;
+   ratio  = fill;
+   size   = "2.0,2.6";
+   node [ shape = record, width = 0, height = 0 ];
+   edge [ color = gray40 ];
+
+   subgraph cluster_all {
+
+     root [
+        label     = "root\nset|<r0> r0|<r1> r1\n*",
+        style     = filled,
+        fillcolor = gray96,
+     ];
+
+     subgraph marked {
+        node [ style = filled, fillcolor = gray25, fontcolor = white ];
+        h1; h2; h5; h6;
+     };
+
+     root:r0 -> h1 [ color = gray10 ];
+     h1 -> h2 [ color = gray10 ];
+     h2 -> h5 [ color = gray10 ];
+     h5 -> h1 [ color = gray10 ];
+     root:r1 -> h6 [ style = bold, color = black ];
+     h6 -> h2;
+     h4 -> h3;
+     h3 -> h5;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g2_6
+
+   margin = 0;
+   ratio  = fill;
+   size   = "2.0,2.6";
+   node [ shape = record, width = 0, height = 0 ];
+   edge [ color = gray40 ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1\n*",
+         style     = filled,
+         fillcolor = gray96,
+      ];
+
+      subgraph marked {
+         node [ style = filled, fillcolor = gray25, fontcolor = white ];
+         h1; h2; h5; h6;
+      };
+
+      root:r0 -> h1 [ color = gray10 ];
+      h1 -> h2 [ color = gray10 ];
+      h2 -> h5 [ color = gray10 ];
+      h5 -> h1 [ color = gray10 ];
+      root:r1 -> h6 [ color = gray10 ];
+      h6 -> h2 [ style = bold, color = black ];
+      h4 -> h3;
+      h3 -> h5;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, parte 2}
+   \end{figure}
+
+
+.. [#gccycle] Un ciclo es un camino donde el *vértice inicial* es el mismo
+   que el *vértice final*. Por lo tanto, los *vértices terminales* son
+   completamente arbitrarios, ya que cualquier *vértice interior* puede ser
+   un *vértice terminal*.
+.. [#gcpseudo] Para presentar los algoritmos se utiliza una forma simple de
+   pseudo-código. El pseudo-código se escribe en inglés para que pueda ser
+   más fácilmente contrastado con la literatura, que está en inglés. Para
+   diferenciar posiciones de memoria y punteros de las celdas en sí, se usa
+   la misma sintaxis que C, ``r*`` denota una referencia o puntero y ``*r``
+   denota "objeto al que apunta ``r``\ ". Se sobreentiende que ``r = o``
+   siempre toma la dirección de memoria de ``o``.
+
+
+
+.. _ref_gc_tricolor:
+
+Abstracción tricolor
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Muchos algoritmos utilizan tres colores para realizar el marcado. El tercer
+color, gris generalmente, indica que una celda debe ser visitada. Esto
+permite algoritmos :ref:`concurrentes <ref_gc_concurrent>`
+e :ref:`incrementales <ref_gc_inc>`, además de otro tipo de optimizaciones.
+Entonces, lo que plantea esta abtracción es una nueva partición del heap al
+momento de marcar, esta vez son 3 porciones: blanca, gris y negra.
+
+Al principio todas las celdas se pintan de blanco, excepto el *root set*
+que se punta de gris. Luego se van obteniendo celdas del conjunto de las
+grises y se las pinta de negro, pintando sus hijas directas de gris.
+
+Una vez que no hay más celdas grises, tenemos la garantía de que las celdas
+negras serán el *live set* y las celdas blancas *basura*. Esto se debe
+a que siempre se mantiene esta invariante: **ninguna celda negra apunta
+directamente a una celda blanca**. Las celdas blancas siempre son apuntadas
+por celdas blancas o grises. Entonces, siempre que el conjunto de celdas
+grises sea vacío, no habrán celdas negras conectadas a blancas, siendo las
+celdas blancas *basura*.
+
+El algoritmo básico para marcar con tres colores es el siguiente (asumiendo
+que todas las celdas parten pintadas de blanco, es decir, el conjunto
+blanco contiene todas las celdas de memoria y los conjuntos negro y gris
+están vacíos)::
+
+   mark_phase()
+      for r in root_set
+         gray_set.add(r)
+      while not gray_set.empty()
+         v = gray_set.pop()
+         black_set.add(v)
+         for (src, dst) in v.edges
+            if v in white_set
+               white_set.remove(v)
+               gray_set.add(v)
+
+Es simple notar que este algoritmo es naturalmente no recursivo, lo que de
+por sí ya presenta una ventaja sobre el marcado *bicolor*.
+
+
+
+.. _ref_gc_services:
+
+Servicios
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+En general todos los algoritmos de recolección de basura utilizan servicios
+de una capa inferior [#gclowlayer]_ y proveen servicios a una capa superior
+[#gchilayer]_.
+
+A continuación se presentan las primitivas en común que utilizan todos los
+recolectores a lo largo de este documento.
+
+Servicios utilizados por el recolector son los siguientes:
+
+:math:`alloc() \to cell`:
+   obtiene una nueva celda de memoria. El mecanismo por el cual se obtiene
+   la celda es indistinto para esta sección, puede ser de una lista libre,
+   puede ser de un administrador de memoria de más bajo nivel provisto por
+   el sistema operativo o la biblioteca estándar de C (``malloc()``), etc.
+   Cómo organizar la memoria es un área de investigación completa y si bien
+   está estrechamente relacionada con la recolección de basura, en este
+   trabajo no se prestará particular atención a este aspecto (salvo casos
+   donde el recolector impone una cierta organización de memoria en el *low
+   level allocator*). Por simplicidad también asumiremos (a menos que se
+   indique lo contrario) que las celdas son de tamaño fijo. Esta restricción
+   normalmente puede ser fácilmente relajada (en los recolectores que la
+   tienen).
+
+:math:`free(cell)`:
+   libera una celda que ya no va a ser utilizada. La celda liberada debe
+   haber sido obtenida mediante ``alloc()``.
+
+Y los servicios básicos proporcionados por el recolector son los
+siguientes:
+
+:math:`new() \to cell`:
+   obtiene una celda de memoria para ser utilizada por el programa.
+
+:math:`update(ref, cell)`:
+   notifica al recolector que la referencia :math:`ref` ahora apunta
+   a :math:`cell`. Visto más formalmente, sería análogo a decir que hubo un
+   cambio en la conectividad del grafo: la arista :math:`src \to old` cambia
+   por :math:`src \to new` (donde :math:`src` es la celda que contiene la
+   referencia :math:`ref`, :math:`old` es la celda a la que apunta la
+   referencia :math:`ref` y :math:`new` es el argumento :math:`cell`). Si
+   :math:`cell` es ``null``, sería análogo a informar que se elimina la
+   arista :math:`src \to old`.
+
+:math:`del(cell)`:
+   este servicio, según el algoritmo, puede ser utilizado para informar un
+   cambio en la conectividad del grafo, la eliminación de una arista
+   (análogo a :math:`update(ref, null)` pero sin proporcionar información
+   sobre la arista a eliminar). Esto es generalmente útil solo en
+   :ref:`conteo de referencias <ref_gc_rc>`. Para otros recolectores puede
+   significar que el usuario asegura que no hay más referencias a esta
+   celda, es decir, análogo a eliminar el conjunto de aristas
+   :math:`\big\lbrace (v, w) \in A , v \in Live \thickspace set , w \in
+   Live \thickspace set \big/ w = cell`.
+
+:math:`collect()`:
+   indica al recolector que debe hacer un análisis del grafo de conectividad
+   en busca de *basura*. Generalmente este servicio es invocado por el
+   propio recolector cuando no hay más celdas reciclables.
+
+No todos los servicios son implementados por todos los recolectores, pero
+son lo suficientemente comunes como para describirlos de forma general en
+esta sección. Algunos son principalmente ideados para uso interno del
+recolector, aunque en ciertas circunstancias pueden ser utilizados por el
+usuario también.
+
+
+.. [#gclowlayer] En general estos servicios están provistos directamente
+   por el sistema operativo pero también pueden estar dados por un
+   administrador de memoria de bajo nivel (o *low level allocator* en
+   inglés).
+.. [#gchilayer] En general estos servicios son utilizados directamente por
+   el lenguaje de programación, pero pueden ser utilizados directamente por
+   el usuario del lenguaje si éste interatúa con el recolector, ya sea por
+   algún requerimiento particular o porque el lenguaje no tiene soporte
+   diercto de recolección de basura y el recolector está implementado como
+   una biblioteca de usuario.
+
+
+
+.. _ref_gc_clasic:
+
+Algoritmos clásicos
 ----------------------------------------------------------------------------
 
-TODO
+En la literatura se encuentran normalmente referencias a 3 algoritmos
+clásicos, que son utilizados generalmente como bloques básicos para
+construir recolectores más complejos. Se presentan las versiones históricas
+más simples a fin de facilitar la comprensión conceptual.
+
 
 
+.. _ref_gc_rc:
 
 Conteo de referencias
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-TODO
+Se trata del algoritmo más antiguo de todos, implementado por primera vez
+por `John McCarthy`_ para Lisp_ a finales de 1950. Se trata de un método
+:ref:`directo <ref_gc_direct>` e :ref:`incremental <ref_gc_inc>` por
+naturaleza, ya que distribuye la carga de la recolección de basura durante
+toda la ejecución del programa, cada vez que el *mutator* cambia la
+conectividad de algún nodo del grafo de conectividad.
+
+El método consiste en tener un contador asociado a cada celda que contenga
+la cantidad de celdas **vivas** que apuntan a ésta. Es decir, es la
+cardinalidad del conjunto de aristas que tienen por destino a la celda.
+Formalmente podemos definir el contador math:`rc(v)` (de *reference
+counter* en inglés) de la siguiente manera:
+
+.. math::
 
+   rc(v) = \big\lvert
+      \left\lbrace
+         (v_1, v_2) \in A \big/
+            v_1 \in Live \thickspace set \cup Root \thickspace set
+               \wedge v_2 = v
+      \right\rbrace
+   \big\rvert
+
+El *mutator* entonces debe actualizar este contador cada vez que el grafo
+de conectividad cambia, es decir, cada vez que se agrega, modifica
+o elimina una arista del grafo (o visto de una forma más cercana al código,
+cada vez que se agrega, modifica o elimina un puntero).
+
+Esta invariante es fundamental para el conteo de referencias, porque se
+asume que si el contador es 0 entonces el *mutator* no tiene ninguna
+referencia a la celda y por lo tanto es *basura*:
+
+.. math::
+
+   rc(v) = 0 \Rightarrow v \in Basura
+
+Para mantener esta invariante el *mutator*, cada vez que cambia un puntero
+debe decrementar en 1 el contador de la celda a la que apuntaba
+antiguamente  e incrementar en 1 el contador de la celda a la que apunta
+luego de la modificación. Esto asegura que la invariante se mantenga
+durante toda la ejecución del programa. Si al momento de decrementar un
+contador éste queda en 0, la celda asociada debe liberarse de forma de
+poder ser reciclada. Esto implica que si esta celda almacena punteros, los
+contadores de las celdas apuntadas deben ser decrementados también, porque
+solo deben almacenarse en el contador las aristas del *live set* para
+mantener la invariante. De esto puede resultar que otros contadores de
+referencia queden en 0 y más celdas sean liberadas. Por lo tanto,
+teóricamente la complejidad de eliminar una referencia puede ser
+:math:`O(\lvert Live \thickspace set \rvert)` en el peor caso.
+
+Las primitivas implementadas para este tipo de recolector son las
+siguientes (acompañadas de una implementación básica)::
+
+   new()
+      cell = alloc()
+      if cell is null
+         throw out_of_memory
+      cell.rc = 1
+      return cell
+
+   del(cell)
+      cell.rc = cell.rc - 1
+      if cell.rc is 0
+         for child* in cell.children
+            del(*child)
+         free(cell)
+
+   update(ref*, cell)
+      cell.rc = cell.rc + 1
+      del(*ref)
+      *ref = cell
+
+
+Ejemplo
+^^^^^^^
+
+A continuación se presenta un ejemplo gráfico para facilitar la comprensión
+del algoritmo.
+
+Por simplicidad se asumen celdas de tamaño fijo con dos punteros, ``left``
+y ``right`` (estructura clásica para representar un árbol binario) y se
+muestra el contador de referencias abajo del nombre de cada celda. Se parte
+con una pequeña estructura ya construída y se muestra primero lo que ocurre
+al eliminar la referencia :math:`r0 \to h1`:
+
+.. TODO: figure
+
+.. raw:: latex
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO]{
+
+.. digraph:: g3_1
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      h1 [ label = "h1\n1|<l> left|<r> right" ];
+      h2 [ label = "h2\n2|<l> left|<r> right" ];
+      h3 [ label = "h3\n2|<l> left|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r0 -> h1 [ style = bold, color = black ];
+      root:r1 -> h3;
+      h1:l -> h2;
+      h1:r -> h3;
+      h2:l -> h4;
+      h2:r -> h5;
+      h3:l -> h2;
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g3_2
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h1;
+      };
+
+      h1 [ label = "h1\n0|<l> left|<r> right" ];
+      h2 [ label = "h2\n2|<l> left|<r> right" ];
+      h3 [ label = "h3\n2|<l> left|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r0 -> h1 [ style = invis ];
+      root:r1 -> h3;
+      h1:l -> h2 [ style = bold, color = black ];
+      h1:r -> h3;
+      h2:l -> h4;
+      h2:r -> h5;
+      h3:l -> h2;
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, part 1}
+   \end{figure}
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO]{
+
+.. digraph:: g3_3
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0\n*|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h1;
+      };
+
+      h1 [ label = "h1\n0|<l> left|<r> right" ];
+      h2 [ label = "h2\n1|<l> left|<r> right" ];
+      h3 [ label = "h3\n2|<l> left|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r0 -> h1 [ style = invis ];
+      root:r1 -> h3;
+      h1:l -> h2 [ style = invis ];
+      h1:r -> h3 [ style = bold, color = black ];
+      h2:l -> h4;
+      h2:r -> h5;
+      h3:l -> h2;
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g3_4
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h1;
+      };
+
+      h1 [ label = "h1\n0|<l> left|<r> right" ];
+      h2 [ label = "h2\n1|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r0 -> h1 [ style = invis ];
+      root:r1 -> h3;
+      h1:l -> h2 [ style = invis ];
+      h1:r -> h3 [ style = invis ];
+      h2:l -> h4;
+      h2:r -> h5;
+      h3:l -> h2;
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, parte 2}
+   \end{figure}
+
+Como se observa, la celda ``h1`` queda con el contador en 0, por lo tanto
+pasa a ser *basura*. Los contadores de las celdas a las que apuntaban
+``h1.left`` y ``h1.right`` son decrementados, pero no se detecta más basura
+porque sigue existiendo un camino del *root set* a aquellas celdas, y por
+transitividad a todas aquellas celdas apuntadas por éstas. Es por esto que
+no es necesario seguir recorriendo el grafo de conectividad.
+
+A continuación se muestra como opera el algoritmo al cambiar a donde apunta
+``h3.left``, haciéndola apuntar a ``h5``. Es decir, que pasa luego de la
+operación ``update(h3.left, h5)`` (por simplicidad no se muestra más la
+celda ``h1`` que ahora es *basura*):
+
+.. TODO: figure
+
+.. raw:: latex
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO]{
+
+.. digraph:: g4_1
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+      };
+
+      h2 [ label = "h2\n1|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r1 -> h3;
+      h2:l -> h4;
+      h2:r -> h5;
+      h3:l -> h2 [ style = bold, color = black ];
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g4_2
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+      };
+
+      h2 [ label = "h2\n1|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n2|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r1 -> h3;
+      h2:l -> h4;
+      h2:r -> h5;
+      h3:l -> h2 [ style = bold, color = black ];
+      h3:l -> h5 [ style = dotted, color = black ];
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, part 1}
+   \end{figure}
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO]{
+
+.. digraph:: g4_3
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h2;
+      };
+
+      h2 [ label = "h2\n0|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
+      h4 [ label = "h4\n1|<l> left|<r> right" ];
+      h5 [ label = "h5\n2|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r1 -> h3;
+      h2:l -> h4 [ style = bold, color = black ];
+      h2:r -> h5;
+      h3:l -> h2 [ style = invis ];
+      h3:l -> h5 [ style = dotted, color = black ];
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g4_4
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h2; h4;
+      };
+
+      h2 [ label = "h2\n0|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
+      h4 [ label = "h4\n0|<l> left|<r> right" ];
+      h5 [ label = "h5\n2|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r1 -> h3;
+      h2:l -> h4 [ style = invis ];
+      h2:r -> h5 [ style = bold, color = black ];
+      h3:l -> h2 [ style = invis ];
+      h3:l -> h5 [ style = dotted, color = black ];
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, part 2}
+   \end{figure}
+
+   \begin{figure}[htp]
+   \centering
+   \subfigure[TODO]{
+
+.. digraph:: g4_5
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h2; h4;
+      };
+
+      h2 [ label = "h2\n0|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
+      h4 [ label = "h4\n0|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r1 -> h3;
+      h2:l -> h4 [ style = invis ];
+      h2:r -> h5 [ style = invis ];
+      h3:l -> h5 [ style = bold, color = black ];
+      h3:l -> h2 [ style = invis ];
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \subfigure[TODO]{
+
+.. digraph:: g4_6
+
+   margin = 0;
+   ratio  = fill;
+   size   = "3.0,3.8";
+   edge [ color = gray40 ];
+   node [
+      shape     = record,
+      width     = 0,
+      height    = 0,
+      style     = filled,
+      fillcolor = gray25,
+      fontcolor = white
+   ];
+
+   subgraph cluster_all {
+
+      root [
+         label     = "root\nset|<r0> r0|<r1> r1",
+         style     = filled,
+         fillcolor = gray96,
+         fontcolor = black,
+      ];
+
+      subgraph marked {
+         node [ fillcolor = white, fontcolor = black ];
+         h2; h4;
+      };
+
+      h2 [ label = "h2\n0|<l> left|<r> right" ];
+      h3 [ label = "h3\n1|<l> left|<r> right" ];
+      h4 [ label = "h4\n0|<l> left|<r> right" ];
+      h5 [ label = "h5\n1|<l> left|<r> right" ];
+      h6 [ label = "h6\n1|<l> left|<r> right" ];
+
+      root:r1 -> h3;
+      h2:l -> h4 [ style = invis ];
+      h2:r -> h5 [ style = invis ];
+      h3:l -> h5;
+      h3:l -> h2 [ style = invis ];
+      h3:r -> h6;
+
+   }
+
+.. raw:: latex
+
+   }
+   \caption{TODO, parte 3}
+   \end{figure}
+
+.. _ref_gc_cycles:
+
+TODO El problema de los ciclos
 
 
 Marcado y barrido
@@ -134,6 +1383,99 @@ TODO
 
 
 
+Clasificación
+----------------------------------------------------------------------------
+
+La cantidad de clasificaciones que pueden hacerse respecto a algoritmos de
+recolección de basura son muy grandes. Muchas de estas clasificaciones se
+superponen entre sí, habiendo algoritmos que aplican muchas técnicas a la
+vez o recolectores híbridos que aplican una técnica para algún tipo de
+objeto y otra para otros.
+
+A continuación se enumeran las clasificaciones más importantes que se
+pudieron observar en la investigación sobre el `estado del arte`_.
+
+.. _ref_gc_direct:
+
+Directa / indirecta
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generalmente se llama recolección **directa** a aquella en la cual el
+compilador o lenguaje instrumenta al *mutator* de forma tal que la
+información de conectividad se mantenga activamente cada vez que hay un
+cambio en él. Normalmente se utiliza un contador de referencia en cada
+celda para este propósito, permitiendo almacenar en todo momento la
+cantidad de nodos que apuntan a ésta (dejando de lado el :ref:`problema de
+los ciclos <ref_gc_cycles>`). Esto permite reclamar una celda
+instantáneamente cuando el *mutator* deja de hacer referencia a ella. Este
+tipo de recolectores son, inherentemente :ref:`incrementales <ref_gc_inc>`.
+
+Por el contrario, los recolectores **indirectos** normalmente no
+interfieren con el *mutator* en cada actualización del grafo de
+conectividad (exceptuando algunos :ref:`recolectores incrementales
+<ref_gc_inc>` que a veces necesitan instrumentar el *mutator* pero no para
+mantener el estado del grafo de conectividad completo). La recolección se
+dispara usualmente cuando el *mutator* requiere alocar memoria pero no hay
+más memoria libre conocida disponible y el recolector se encarga de generar
+la información de conectividad desde cero para determinar qué celdas son
+*basura*.
+
+Estas son las dos grandes familias de recolectores, también conocidos como
+`conteo de referencias`_ (directa) y *traicing garbage collection*
+(indirecta).
+
+
+.. _ref_gc_inc:
+
+Incremental
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Recolección incremental es aquella que se realiza de forma intercalada con
+el *mutator*. En general el propósito es disminuir el tiempo de las pausas
+causadas por el recolector (aunque generalmente el resultado es un mayor
+costo en tiempo total de recolección).
+
+De los `algoritmos clásicos`_ el único que es incremental en su forma más
+básica es el `conteo de referencias`_. Otros recolectores pueden hacerse
+incrementales de diversas maneras, pero en general consta de hacer parte
+del trabajo de escanear el grafo de conectividad cada vez que el *mutator*
+aloca memoria. En general para hacer esto es también necesario instrumentar
+al *mutator* de forma tal que informe al recolector cada vez que cambia el
+grafo de conectividad, para que éste pueda marcar al sub-grafo afectado por
+el cambio como *desactualizado* y así re-escanearlo nuevamente en la
+próxima iteración.
+
+En general la eficiencia de los recolectores incrementales disminuye
+considerablemente cuando el *mutator* actualiza muy seguido el grafo de
+conectividad, porque debe re-escanear sub-grafos que ya había escaneado una
+y otra vez. A esto se debe también que en general el tiempo de
+procesamiento total de un recolector incremental sea mayor que uno no
+incremental, aunque el tiempo de pausa de una recolección sea menor.
+
+
+.. _ref_gc_concurrent:
+
+Concurrente / *stop-the-world*
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Los recolectores concurrentes son aquellos que pueden correr en paralelo
+con el *mutator*. Por el contrario, aquellos que pausan el *mutator* para
+realizar la recolección son usualmente denominados *stop-the-world* (*parar
+el mundo*), haciendo referencia a que pausan todos los hilos del *mutator*
+para poder escanear el grafo de conectividad de forma consistente.
+
+Para lograr que un recolector sea concurrente generalmente el mecanismo es
+similar al necesario para hacer un :ref:`recolector incremental
+<ref_gc_inc>`: hay que instrumentar al *mutator* para que informe al
+recolector cuando se realiza algún cambio en el grafo de conectividad, de
+forma tal que pueda volver a escanear el sub-grafo afectado por el cambio.
+
+Esto también trae como consecuencia el incremento en el tiempo total que
+consume el recolector, debido a la necesidad de re-escanear sub-grafos que
+han sido modificados.
+
+.. _ref_gc_art:
+
 Estado del arte
 ----------------------------------------------------------------------------
 
@@ -142,7 +1484,60 @@ Estado del arte
 
 TODO
 
+Cloning
+
+
+1. Instrumentar el *mutator* de forma tal de que informe al recolector cada
+   vez que cambia el grafo de conectividad, de manera que pueda re-escanear
+   el sub-grafo que afectado por el cambio.
+
+2. Tomar una foto de la memoria y escanear esa foto estática en vez de la
+   memoria original, de forma que cualquier cambio en del *mutator* no
+   afecte la vista de la memoria del recolector.
+
+Ambos métodos tienen ventajas y desventajas. El primero no necesita hacer
+una copia costosa de la memoria, pero existe la posibilidad de que el
+recolector nunca pueda escanear el grafo de conectividad completo, si el
+*mutator* modifica el grafo más rápido de lo que el recolector lo escanea.
+Si bien hay formas de evitar esto, es usual que el trabajo de recolección
+se vea considerablemente incrementado por la cantidad de veces que hay que
+re-escanear el grafo. El segundo método puede ser costoso por las copias
+necesarias (aunque esto puede ser mitigado empleando alguna forma de *COW*
+[#gccow]_) y existe la posibilidad de que no se recuperen celdas que el
+*mutator*
+
+
+.. [#gccow] *COW* (del inglés *Copy On Write* o *copiar al escribir*) es
+   una técnica muy utilizada para disminuir las copias innecesarias,
+   evitando hacer la copia hasta que haya una modificación. Mientras no
+   hayan modificaciones no es necesario realizar una copia porque todos los
+   interesados verán la misma información. Esta técnica es utilizada por el
+   *kernel* de Linux_ por ejemplo, para que varias instancias de un mismo
+   proceso puedan compartir la memoria.
+
+
+Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative
+Environment", Software Practice & Experience, September 1988, pp. 807-820.
+http://www.hpl.hp.com/personal/Hans_Boehm/spe_gc_paper/preprint.pdf
+(http://www.hpl.hp.com/personal/Hans_Boehm/spe_gc_paper/)
+
+Boehm, H., "Space Efficient Conservative Garbage Collection", Proceedings
+of the ACM SIGPLAN '93 Conference on Programming Language Design and
+Implementation, SIGPLAN Notices 28, 6 (June 1993), pp. 197-206.
+http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi93.ps.Z
+
+Boehm, H., A. Demers, and S. Shenker, "Mostly Parallel Garbage Collection",
+Proceedings of the ACM SIGPLAN '91 Conference on Programming Language
+Design and Implementation, SIGPLAN Notices 26, 6 (June 1991), pp. 157-164.
+http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi91.ps.Z
+
+Implementación de Bohem GC
+http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcdescr.html
+
+Interfaz de Bohem GC
+http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html
+
 
 .. include:: links.rst
 
-.. vim: set ts=2 sts=2 sw=2 et tw=75 :
+.. vim: set ts=3 sts=3 sw=3 et tw=75 :
index e3614d063cada06d96dbd8c464dc481c0cada42d..de70415ca866eb92ad8b8d6f98347d1458338148 100644 (file)
    International Symposium on Computer Architecture on High Performance
    Computing - Volume 00 (páginas 35-43), 2005.
 
+.. [BEZO06] Emery D. Berger, Benjamin G. Zorn. DieHard: probabilistic
+   memory safety for unsafe languages. PLDI '06: Proceedings of the 2006
+   ACM SIGPLAN conference on Programming language design and
+   implementation. 2006. ISBN 1-59593-320-4.
+
 
 .. include:: links.rst