]> git.llucax.com Git - z.facultad/75.00/informe.git/blob - source/gc.rst
100614f6c537ddc5df723237110ee4bd50e5aea5
[z.facultad/75.00/informe.git] / source / gc.rst
1
2 .. Introducción a la importancia de la recolección de basura y sus
3    principales técnicas, con sus ventajas y desventajas. También se da
4    un breve recorrido sobre el estado del arte.
5    ESTADO: SIN EMPEZAR
6
7
8 .. _ref_gc:
9
10 Recolección de basura
11 ============================================================================
12
13
14 Introducción
15 ----------------------------------------------------------------------------
16
17 *Recolección de basura* se refiere a la recuperación automática de memoria
18 del *heap* [#gcheap]_ una vez que el programa ha dejado de hacer referencia
19 a ella (y por lo tanto, ha dejado de utilizarla).
20
21 A medida que el tiempo pasa, cada vez los programas son más complejos y es
22 más compleja la administración de memoria. Uno de los aspectos más
23 importantes de un recolector de basura es lograr un mayor nivel de
24 abstracción y modularidad, dos conceptos claves en la ingeniería de
25 software [JOLI96]_. En particular, al diseñar o programar bibliotecas, de
26 no haber un recolector de basura, **la administración de memoria pasa a ser
27 parte de la interfaz**, lo que produce que los módulos tengan un mayor
28 grado de acoplamiento.
29
30 Además hay una incontable cantidad de problemas asociados al manejo
31 explícito de memoria que simplemente dejan de existir al utilizar un
32 recolector de basura. Por ejemplo, los errores en el manejo de memoria
33 (como *buffer overflows* [#gcbuff]_ o *dangling pointers* [#gcdang]_) son
34 la causa más frecuente de problemas de seguridad [BEZO06]_.
35
36 La recolección de basura nació junto a Lisp_ a finales de 1950 y en los
37 siguientes años estuvo asociada principalmente a lenguajes funcionales,
38 pero en la actualidad está presente en prácticamente todos los lenguajes de
39 programación, de alto o bajo nivel, aunque sea de forma opcional. En los
40 últimos 10 años tuvo un gran avance, por la adopción en lenguajes de
41 desarrollo rápido utilizados mucho en el sector empresarial, en especial
42 Java_, que fue una plataforma de facto para la investigación y desarrollo
43 de recolectores de basura (aunque no se limitaron a este lenguaje las
44 investigaciones).
45
46 En las primeras implementaciones de recolectores de basura la penalización
47 en la eficiencia del programa se volvía prohibitiva para muchas
48 aplicaciones. Es por esto que hubo bastante resistencia a la utilización de
49 recolectores de basura, pero el avance en la investigación fue haciendo que
50 cada vez sea una alternativa más viable al manejo manual de memoria,
51 incluso para apliaciones con altos requerimientos de eficiencia. En la
52 actualidad un programa que utiliza un recolector moderno puede ser
53 comparable en eficiencia con uno que utiliza un esquema manual. En
54 particular, si el programa fue diseñado con el recolector de basura en
55 mente en ciertas circunstancias puede ser incluso más eficiente que uno que
56 hace manejo explícito de la memoria. Muchos recolectores mejoran la
57 localidad de referencia, haciendo que el programa tenga un mejor
58 comportamiento con el caché y la memoria virtual.
59
60 El recolector de basura debe tener un comportamiento correcto y predecible
61 para que sea útil, si el programador no puede confiar en el recolector
62 de basura, éste se vuelve más un problema que una solución, porque
63 introduce nuevos puntos de falla en los programas, y lo que es peor,
64 puntos de falla no controlados por el programador, volviendo mucho más
65 difícil la búsqueda de errores.
66
67
68 .. [#gcheap] *Heap* es un área de memoria que se caracteriza por ser
69    dinámica (a diferencia del área de memoria estática que está disponible
70    durante toda la ejecución de un programa). Un programa puede reservar
71    memoria en tiempo de ejecución según sea necesario y liberarla cuando ya
72    no la necesita. A diferencia del *stack*, la duración de la *reserva* no
73    está atada a un bloque de código.
74 .. [#gcbuff] Un *buffer overflow* (*desbordamiento de memoria* en
75    castellano) se produce cuando se copia un dato a un área de memoria que
76    no es lo suficientemente grande para contenerlo. Esto puede producir que
77    el programa sea abortado por una violación de segmento, o peor,
78    sobreescribir un área de memoria válida, en cuyo caso los resultados son
79    impredecibles.
80 .. [#gcdang] Un *dangling pointer* (*puntero colgante* en castellano) es un
81    puntero que apunta a un área de memoria inválida. Ya sea porque el
82    elemento apuntado no es el mismo tipo o porque la memoria ya ha sido
83    liberada. Al ser desreferenciado, los resultados son impredecibles, el
84    programa podría abortarse por una violación de segmento o podrían pasar
85    peores cosas si el área de memoria fue realocada para almacenar otro
86    objeto.
87
88
89
90 Conceptos básicos
91 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
92
93 Los programas pueden hacer uso principalmente de 4 áreas de memoria:
94
95 Registros:
96    Se trata de la memoria más básica de una computadora. Es el área de
97    memoria en la que puede operar realmente el procesador, es extremadamente
98    escasa y generalmente su uso es administrado por el lenguaje de
99    programación (o compilador más específicamente). Excepto en situaciones
100    muy particulares, realizando tareas de muy bajo nivel, un programador
101    nunca manipula los registros explícitamente.
102
103 Área de memoria estática:
104    Es la forma de memoria más simple que un programador utiliza
105    explícitamente. En general las variables globales se almacenan en este
106    área, que es parte inherente del programa y está disponible durante toda
107    su ejecución, por lo tanto nunca cambia su capacidad en tiempo de
108    ejecución. Es la forma más básica de administrar memoria, pero tiene una
109    limitación fundamental: **el tamaño de la memoria tiene que ser conocido
110    en tiempo de compilación**. Los primeros lenguajes de programación solo
111    contaban con este tipo de memoria (además de los registros del
112    procesador).
113
114 *Stack* (pila):
115    Los primeros lenguajes de programación que hicieron uso de una pila
116    aparecieron en el año 1958 (Algol-58 y Atlas Autocode) y fueron los
117    primeros en introducir estructura de bloques, almacenando las
118    variables locales a estos bloques utilizando una pila [JOLI96]_.
119    Esto permite utilizar recursividad y tener un esquema simple de memoria
120    dinámica. Sin embargo este esquema es muy limitado porque el orden de
121    reserva y liberación de memoria tiene que estar bien establecido. Una
122    celda [#gccelda]_ alocada antes que otra nunca puede ser liberada antes
123    que aquella.
124
125 *Heap*:
126    A diferencia del *stack*, el *heap* provee un área de memoria que puede
127    ser obtenida dinámicamente pero sin limitaciones de orden. Es el tipo de
128    memoria más flexible y por lo tanto el más complejo de administrar; razón
129    por la cual existen los recolectores de basura.
130
131 La recolección de basura impone algunas restricciones sobre la manera de
132 utilizar el *heap*. Debido a que un recolector de basura debe ser capaz de
133 determinar el grafo de conectividad de la memoria en uso, es necesario que
134 el programa siempre tenga alguna referencia a las celdas activas en los
135 registros, memoria estática o *stack* (normalmente denominado *root set*).
136
137 Esto implica que una celda sea considerada basura si y sólo si no puede ser
138 alcanzada a través del grafo de conectividad que se comienza a recorrer
139 desde el *root set*. Por lo tanto, una celda está *viva* si y sólo si su
140 dirección de memoria está almacenada en una celda *raíz* (parte del *root
141 set*) o si está almacenada en otra celda *viva* del *heap*.
142
143 Expresado más formalmente, dada la relación :math:`M \to N`, donde
144 :math:`M` es una celda del *heap* o parte del *root set* y :math:`N` es una
145 celda del *heap*, definida como:
146
147 .. math::
148
149    M \to N \Longleftrightarrow M \text{ almacena un puntero a } N
150
151 El conjunto de celdas vivas (o *live set*) queda determinado por:
152
153 .. math::
154
155    vivas = \left\lbrace N \in Celdas \big/
156       ( \exists r \in Raices / r \to N ) \vee (\exists M \in vivas / M \to N )
157    \right\rbrace
158
159 Cabe aclarar que esta es una definición conceptual, asumiendo que el
160 programa siempre limpia una dirección de memoria almacenada en el *root
161 set* o una celda del *heap* cuando la celda a la que apunta no va a ser
162 utilizada nuevamente. Esto no es siempre cierto y los falsos positivos que
163 esto produce se conoce como un tipo de pérdida de memoria (que es posible
164 incluso al utilizar un recolector de basura) llamada pérdida de memoria
165 *lógica*. Esto puede no ser evitable (incluso cuando el programador no
166 cometa errores) en lenguajes de programación que requieran un recolector de
167 basura conservativo.
168
169 Por último, siendo que el recolector de basura es parte del programa de
170 forma indirecta, es común ver en la literatura que se direfencia entre
171 2 partes del programa, el recolector de basura y el programa en sí. Dado
172 que para el recolector de basura, lo único que interesa conocer del
173 programa en sí son los cambios al grafo de conectividad de las celdas,
174 normalmente se lo llama *mutator* (mutador).
175
176
177 .. [#gccelda] En general en la literatura se nombra a una porción de
178    memoria alocada individualmente *celda*, *nodo* u *objeto*
179    indistintamente. En este trabajo se utilizará la misma nomenclatura
180    (haciendo mención explícita cuando alguno de estos términos se refiera
181    a otra cosa, como al nodo de una lista o a un objeto en el sentido de
182    programación orientada a objetos).
183
184
185
186 Recorrido del grafo de conectividad
187 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188
189 El problema de encontrar las celdas *vivas* de un programa se reduce a recorrer
190 un grafo dirigido. El grafo se define como:
191
192 .. math::
193
194    G = (V,A)
195
196 Donde :math:`V` es el conjunto de vértices, dado por las celdas de memoria
197 y :math:`A` es un conjunto de pares ordenados (aristas), dado por la
198 relación :math:`M \rightarrow N` (es decir, los punteros).
199
200 El grafo comienza a recorrerse desde el *root set* y todos los vértices que
201 fueron visitados componen el *live set*; el resto de los vértices son
202 *basura*.
203
204 Más formalmente, Definimos:
205
206 *Camino*:
207    secuencia de vértices tal que cada uno de los vértices tiene una arista
208    al próximo vértice en la secuencia. Todo camino finito tiene un *vértice
209    inicial* y un *vértice final* (llamados en conjunto *vértices
210    terminales*). Cualquier vértice no terminal es denominado *vértice
211    interior*.
212
213    .. math::
214
215       \underset{v_1 \rightarrow v_N}{C} = \left\lbrace
216          v_1, \dotsc, v_N \in V \big/ \underset{i \in [1,N-1]}{\forall v_i}
217             \exists (v_i \to v_{i+1}) \in A
218       \right\rbrace
219
220 *Conexión*:
221    decimos que :math:`M` está *conectado* a :math:`N` si y sólo si existe un
222    camino de :math:`M` a :math:`N`.
223
224    .. math::
225
226       M \mapsto N \Longleftrightarrow \exists \underset{M \to N}{C} \in G
227
228 *Live set*:
229    el conjunto de celdas *vivas* está dado por todos los vértices
230    (:math:`v`) del grafo para los cuales existe una raíz en el *root set*
231    que esté conectada a él.
232
233    .. math::
234
235       Live \thickspace set = \left\lbrace v \in V \big/
236          \left( \exists r \in Root \thickspace set \big/ r \mapsto v \right)
237       \right\rbrace
238
239 *Basura*:
240    la basura, o celdas *muertas*, quedan determinadas entonces por todas las
241    celdas del *heap* que no son parte del *live set*.
242
243    .. math::
244
245       Basura = V - Live \thickspace set
246
247 Esto es, efectivamente, una partición del *heap*.
248
249 .. TODO: figure
250
251 .. raw:: latex
252
253    \begin{figure}[htp] \centering
254
255 .. digraph:: g1
256
257    margin  = 0;
258    ratio   = fill;
259    size    = "4.6,3.6";
260    node [ shape = record, width = 0, height = 0 ];
261
262    subgraph cluster_heap {
263       label = "Heap";
264       style     = dashed;
265       color     = gray40;
266       fontcolor = gray40;
267
268       subgraph cluster_live {
269          label     = "Live set";
270          style     = dashed;
271          color     = gray40;
272          fontcolor = gray40;
273          node [
274             style     = filled,
275             fillcolor = gray25,
276             fontcolor = white,
277          ];
278          h1; h2; h4; h5; h6;
279       }
280
281       subgraph cluster_garbage {
282          label     = "Basura";
283          style     = dashed;
284          color     = gray40;
285          fontcolor = gray40;
286          node [ style = filled, fillcolor = white ];
287          h7; h3;
288       }
289    }
290
291    subgraph cluster_root {
292       label     = "Root set";
293       style     = dashed;
294       color     = gray40;
295       fontcolor = gray40;
296       node [ style = filled, fillcolor = gray96 ];
297       r0; r1; r2;
298    }
299
300    r0 -> h1 -> h2 -> h5;
301    r1 -> h5 -> h6 -> h1;
302    r2 -> h4;
303    h5 -> h4;
304    h7 -> h1;
305    h7 -> h3;
306
307 .. raw:: latex
308
309    \caption{Distintas partes de la memoria, incluyendo relación entre
310    basura, live set, heap y root set.}
311    \end{figure}
312
313 Al proceso de visitar los vértices *conectados* desde el *root set* se lo
314 denomina *marcado*, *fase de marcado* o *mark phase* en inglés, debido
315 a que es necesario marcar los vértices para evitar visitar 2 veces el mismo
316 nodo en casos de que el grafo contenga ciclos [#gccycle]_. De forma similar
317 a la búsqueda, que puede realizarse *primero a lo ancho* (*breadth-first*)
318 o *primero a lo alto* (*depth-first*) del grafo, el marcado de un grafo
319 también puede realizarse de ambas maneras. Cada una podrá o no tener
320 efectos en la eficiencia, en particular dependiendo de la aplicación puede
321 convenir uno u otro método para lograr una mejor localidad de referencia
322 y de esta manera tener un mejor comportamiento de la memoria virtual o del
323 *caché*.
324
325 Un algoritmo simple (recursivo) de marcado *primero a lo alto*  puede ser
326 el siguiente (asumiendo que partimos con todos los vértices sin marcar)
327 [#gcpseudo]_::
328
329    mark(v)
330       if not v.marked
331          v.marked = true
332          for (src, dst) in v.edges
333             mark(dst)
334
335    mark_phase()
336       for r in root_set
337          mark(r)
338
339 Una vez concluido el marcado, sabemos que todos los vértices con la marca
340 son parte del *live set* y que todos los vértices no marcados son *basura*.
341 Esto es conocido también como **abstracción bicolor**, dado que en la
342 literatura se habla muchas veces de *colorear* las celdas. En general, una
343 celda sin marcar es de color blanco y una marcada de color negro.
344
345 .. TODO: figure
346
347 .. raw:: latex
348
349    \begin{figure}[htp]
350    \centering
351    \subfigure[TODO texto más largo y más largo y larguísimo porque tiene
352    muchas cosas que decir]{
353
354 .. digraph:: g2_1
355
356    margin = 0;
357    ratio  = fill;
358    size   = "2.0,2.6";
359    node [ shape = record, width = 0, height = 0];
360    edge [ color = gray40 ];
361
362    subgraph cluster_all {
363
364       root [
365          label     = "root\nset|<r0> r0\n*|<r1> r1",
366          style     = filled,
367          fillcolor = gray96,
368       ];
369
370       subgraph marked {
371          node [ style = filled, fillcolor = gray25, fontcolor = white ];
372          h1;
373       };
374
375       root:r0 -> h1 [ style = bold, color = black ];
376       h1 -> h2 -> h5 -> h1;
377       root:r1 -> h6 -> h2;
378       h4 -> h3;
379       h3 -> h5;
380
381    }
382
383 .. raw:: latex
384
385    }
386    \subfigure[TODO]{
387
388 .. digraph:: g2_2
389
390    margin = 0;
391    ratio  = fill;
392    size   = "2.0,2.6";
393    node [ shape = record, width = 0, height = 0 ];
394    edge [ color = gray40 ];
395
396    subgraph cluster_all {
397
398       root [
399          label     = "root\nset|<r0> r0\n*|<r1> r1",
400          style     = filled,
401          fillcolor = gray96,
402       ];
403
404       subgraph marked {
405          node [ style = filled, fillcolor = gray25, fontcolor = white ];
406          h1; h2;
407       };
408
409       root:r0 -> h1 [ color = gray10 ];
410       h1 -> h2 [ style = bold, color = black ];
411       h2 -> h5 -> h1;
412       root:r1 -> h6 -> h2;
413       h4 -> h3;
414       h3 -> h5;
415
416    }
417
418 .. raw:: latex
419
420    }
421    \subfigure[TODO]{
422
423 .. digraph:: g2_3
424
425    margin = 0;
426    ratio  = fill;
427    size   = "2.0,2.6";
428    node [ shape = record, width = 0, height = 0 ];
429    edge [ color = gray40 ];
430
431    subgraph cluster_all {
432
433       root [
434          label     = "root\nset|<r0> r0\n*|<r1> r1",
435          style     = filled,
436          fillcolor = gray96,
437       ];
438
439       subgraph marked {
440          node [ style = filled, fillcolor = gray25, fontcolor = white ];
441          h1; h2; h5;
442       };
443
444       root:r0 -> h1 [ color = gray10 ];
445       h1 -> h2 [ color = gray10 ];
446       h2 -> h5 [ style = bold, color = black ];
447       h5 -> h1;
448       root:r1 -> h6 -> h2;
449       h4 -> h3;
450       h3 -> h5;
451
452    }
453
454 .. raw:: latex
455
456    }
457    \caption{TODO, part 1}
458    \end{figure}
459
460    \begin{figure}[htp]
461    \centering
462    \subfigure[TODO]{
463
464 .. digraph:: g2_4
465
466    margin = 0;
467    ratio  = fill;
468    size   = "2.0,2.6";
469    node [ shape = record, width = 0, height = 0 ];
470    edge [ color = gray40 ];
471
472    subgraph cluster_all {
473
474       root [
475          label     = "root\nset|<r0> r0\n*|<r1> r1",
476          style     = filled,
477          fillcolor = gray96,
478       ];
479
480       subgraph marked {
481          node [ style = filled, fillcolor = gray25, fontcolor = white ];
482          h1; h2; h5;
483       };
484
485       root:r0 -> h1 [ color = gray10 ];
486       h1 -> h2 [ color = gray10 ];
487       h2 -> h5 [ color = gray10 ];
488       h5 -> h1 [ style = bold, color = black ];
489       root:r1 -> h6 -> h2;
490       h4 -> h3;
491       h3 -> h5;
492
493    }
494
495 .. raw:: latex
496
497    }
498    \subfigure[TODO]{
499
500 .. digraph:: g2_5
501
502    margin = 0;
503    ratio  = fill;
504    size   = "2.0,2.6";
505    node [ shape = record, width = 0, height = 0 ];
506    edge [ color = gray40 ];
507
508    subgraph cluster_all {
509
510      root [
511         label     = "root\nset|<r0> r0|<r1> r1\n*",
512         style     = filled,
513         fillcolor = gray96,
514      ];
515
516      subgraph marked {
517         node [ style = filled, fillcolor = gray25, fontcolor = white ];
518         h1; h2; h5; h6;
519      };
520
521      root:r0 -> h1 [ color = gray10 ];
522      h1 -> h2 [ color = gray10 ];
523      h2 -> h5 [ color = gray10 ];
524      h5 -> h1 [ color = gray10 ];
525      root:r1 -> h6 [ style = bold, color = black ];
526      h6 -> h2;
527      h4 -> h3;
528      h3 -> h5;
529
530    }
531
532 .. raw:: latex
533
534    }
535    \subfigure[TODO]{
536
537 .. digraph:: g2_6
538
539    margin = 0;
540    ratio  = fill;
541    size   = "2.0,2.6";
542    node [ shape = record, width = 0, height = 0 ];
543    edge [ color = gray40 ];
544
545    subgraph cluster_all {
546
547       root [
548          label     = "root\nset|<r0> r0|<r1> r1\n*",
549          style     = filled,
550          fillcolor = gray96,
551       ];
552
553       subgraph marked {
554          node [ style = filled, fillcolor = gray25, fontcolor = white ];
555          h1; h2; h5; h6;
556       };
557
558       root:r0 -> h1 [ color = gray10 ];
559       h1 -> h2 [ color = gray10 ];
560       h2 -> h5 [ color = gray10 ];
561       h5 -> h1 [ color = gray10 ];
562       root:r1 -> h6 [ color = gray10 ];
563       h6 -> h2 [ style = bold, color = black ];
564       h4 -> h3;
565       h3 -> h5;
566
567    }
568
569 .. raw:: latex
570
571    }
572    \caption{TODO, parte 2}
573    \end{figure}
574
575
576 .. [#gccycle] Un ciclo es un camino donde el *vértice inicial* es el mismo
577    que el *vértice final*. Por lo tanto, los *vértices terminales* son
578    completamente arbitrarios, ya que cualquier *vértice interior* puede ser
579    un *vértice terminal*.
580 .. [#gcpseudo] Para presentar los algoritmos se utiliza una forma simple de
581    pseudo-código. El pseudo-código se escribe en inglés para que pueda ser
582    más fácilmente contrastado con la literatura, que está en inglés. Para
583    diferenciar posiciones de memoria y punteros de las celdas en sí, se usa
584    la misma sintaxis que C, ``r*`` denota una referencia o puntero y ``*r``
585    denota "objeto al que apunta ``r``\ ". Se sobreentiende que ``r = o``
586    siempre toma la dirección de memoria de ``o``.
587
588
589
590 .. _ref_gc_tricolor:
591
592 Abstracción tricolor
593 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
594
595 Muchos algoritmos utilizan tres colores para realizar el marcado. El tercer
596 color, gris generalmente, indica que una celda debe ser visitada. Esto
597 permite algoritmos :ref:`concurrentes <ref_gc_concurrent>`
598 e :ref:`incrementales <ref_gc_inc>`, además de otro tipo de optimizaciones.
599 Entonces, lo que plantea esta abtracción es una nueva partición del heap al
600 momento de marcar, esta vez son 3 porciones: blanca, gris y negra.
601
602 Al principio todas las celdas se pintan de blanco, excepto el *root set*
603 que se punta de gris. Luego se van obteniendo celdas del conjunto de las
604 grises y se las pinta de negro, pintando sus hijas directas de gris.
605
606 Una vez que no hay más celdas grises, tenemos la garantía de que las celdas
607 negras serán el *live set* y las celdas blancas *basura*. Esto se debe
608 a que siempre se mantiene esta invariante: **ninguna celda negra apunta
609 directamente a una celda blanca**. Las celdas blancas siempre son apuntadas
610 por celdas blancas o grises. Entonces, siempre que el conjunto de celdas
611 grises sea vacío, no habrán celdas negras conectadas a blancas, siendo las
612 celdas blancas *basura*.
613
614 El algoritmo básico para marcar con tres colores es el siguiente (asumiendo
615 que todas las celdas parten pintadas de blanco, es decir, el conjunto
616 blanco contiene todas las celdas de memoria y los conjuntos negro y gris
617 están vacíos)::
618
619    mark_phase()
620       for r in root_set
621          gray_set.add(r)
622       while not gray_set.empty()
623          v = gray_set.pop()
624          black_set.add(v)
625          for (src, dst) in v.edges
626             if v in white_set
627                white_set.remove(v)
628                gray_set.add(v)
629
630 Es simple notar que este algoritmo es naturalmente no recursivo, lo que de
631 por sí ya presenta una ventaja sobre el marcado *bicolor*.
632
633
634
635 .. _ref_gc_services:
636
637 Servicios
638 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
639
640 En general todos los algoritmos de recolección de basura utilizan servicios
641 de una capa inferior [#gclowlayer]_ y proveen servicios a una capa superior
642 [#gchilayer]_.
643
644 A continuación se presentan las primitivas en común que utilizan todos los
645 recolectores a lo largo de este documento.
646
647 Servicios utilizados por el recolector son los siguientes:
648
649 :math:`alloc() \to cell`:
650    obtiene una nueva celda de memoria. El mecanismo por el cual se obtiene
651    la celda es indistinto para esta sección, puede ser de una lista libre,
652    puede ser de un administrador de memoria de más bajo nivel provisto por
653    el sistema operativo o la biblioteca estándar de C (``malloc()``), etc.
654    Cómo organizar la memoria es un área de investigación completa y si bien
655    está estrechamente relacionada con la recolección de basura, en este
656    trabajo no se prestará particular atención a este aspecto (salvo casos
657    donde el recolector impone una cierta organización de memoria en el *low
658    level allocator*). Por simplicidad también asumiremos (a menos que se
659    indique lo contrario) que las celdas son de tamaño fijo. Esta restricción
660    normalmente puede ser fácilmente relajada (en los recolectores que la
661    tienen).
662
663 :math:`free(cell)`:
664    libera una celda que ya no va a ser utilizada. La celda liberada debe
665    haber sido obtenida mediante ``alloc()``.
666
667 Y los servicios básicos proporcionados por el recolector son los
668 siguientes:
669
670 :math:`new() \to cell`:
671    obtiene una celda de memoria para ser utilizada por el programa.
672
673 :math:`update(ref, cell)`:
674    notifica al recolector que la referencia :math:`ref` ahora apunta
675    a :math:`cell`. Visto más formalmente, sería análogo a decir que hubo un
676    cambio en la conectividad del grafo: la arista :math:`src \to old` cambia
677    por :math:`src \to new` (donde :math:`src` es la celda que contiene la
678    referencia :math:`ref`, :math:`old` es la celda a la que apunta la
679    referencia :math:`ref` y :math:`new` es el argumento :math:`cell`). Si
680    :math:`cell` es ``null``, sería análogo a informar que se elimina la
681    arista :math:`src \to old`.
682
683 :math:`del(cell)`:
684    este servicio, según el algoritmo, puede ser utilizado para informar un
685    cambio en la conectividad del grafo, la eliminación de una arista
686    (análogo a :math:`update(ref, null)` pero sin proporcionar información
687    sobre la arista a eliminar). Esto es generalmente útil solo en
688    :ref:`conteo de referencias <ref_gc_rc>`. Para otros recolectores puede
689    significar que el usuario asegura que no hay más referencias a esta
690    celda, es decir, análogo a eliminar el conjunto de aristas
691    :math:`\big\lbrace (v, w) \in A , v \in Live \thickspace set , w \in
692    Live \thickspace set \big/ w = cell`.
693
694 :math:`collect()`:
695    indica al recolector que debe hacer un análisis del grafo de conectividad
696    en busca de *basura*. Generalmente este servicio es invocado por el
697    propio recolector cuando no hay más celdas reciclables.
698
699 No todos los servicios son implementados por todos los recolectores, pero
700 son lo suficientemente comunes como para describirlos de forma general en
701 esta sección. Algunos son principalmente ideados para uso interno del
702 recolector, aunque en ciertas circunstancias pueden ser utilizados por el
703 usuario también.
704
705
706 .. [#gclowlayer] En general estos servicios están provistos directamente
707    por el sistema operativo pero también pueden estar dados por un
708    administrador de memoria de bajo nivel (o *low level allocator* en
709    inglés).
710 .. [#gchilayer] En general estos servicios son utilizados directamente por
711    el lenguaje de programación, pero pueden ser utilizados directamente por
712    el usuario del lenguaje si éste interatúa con el recolector, ya sea por
713    algún requerimiento particular o porque el lenguaje no tiene soporte
714    diercto de recolección de basura y el recolector está implementado como
715    una biblioteca de usuario.
716
717
718
719 .. _ref_gc_clasic:
720
721 Algoritmos clásicos
722 ----------------------------------------------------------------------------
723
724 En la literatura se encuentran normalmente referencias a 3 algoritmos
725 clásicos, que son utilizados generalmente como bloques básicos para
726 construir recolectores más complejos. Se presentan las versiones históricas
727 más simples a fin de facilitar la comprensión conceptual.
728
729
730
731 .. _ref_gc_rc:
732
733 Conteo de referencias
734 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
735
736 Se trata del algoritmo más antiguo de todos, implementado por primera vez
737 por `John McCarthy`_ para Lisp_ a finales de 1950. Se trata de un método
738 :ref:`directo <ref_gc_direct>` e :ref:`incremental <ref_gc_inc>` por
739 naturaleza, ya que distribuye la carga de la recolección de basura durante
740 toda la ejecución del programa, cada vez que el *mutator* cambia la
741 conectividad de algún nodo del grafo de conectividad.
742
743 El método consiste en tener un contador asociado a cada celda que contenga
744 la cantidad de celdas **vivas** que apuntan a ésta. Es decir, es la
745 cardinalidad del conjunto de aristas que tienen por destino a la celda.
746 Formalmente podemos definir el contador math:`rc(v)` (de *reference
747 counter* en inglés) de la siguiente manera:
748
749 .. math::
750
751    rc(v) = \big\lvert
752       \left\lbrace
753          (v_1, v_2) \in A \big/
754             v_1 \in Live \thickspace set \cup Root \thickspace set
755                \wedge v_2 = v
756       \right\rbrace
757    \big\rvert
758
759 El *mutator* entonces debe actualizar este contador cada vez que el grafo
760 de conectividad cambia, es decir, cada vez que se agrega, modifica
761 o elimina una arista del grafo (o visto de una forma más cercana al código,
762 cada vez que se agrega, modifica o elimina un puntero).
763
764 Esta invariante es fundamental para el conteo de referencias, porque se
765 asume que si el contador es 0 entonces el *mutator* no tiene ninguna
766 referencia a la celda y por lo tanto es *basura*:
767
768 .. math::
769
770    rc(v) = 0 \Rightarrow v \in Basura
771
772 Para mantener esta invariante el *mutator*, cada vez que cambia un puntero
773 debe decrementar en 1 el contador de la celda a la que apuntaba
774 antiguamente  e incrementar en 1 el contador de la celda a la que apunta
775 luego de la modificación. Esto asegura que la invariante se mantenga
776 durante toda la ejecución del programa. Si al momento de decrementar un
777 contador éste queda en 0, la celda asociada debe liberarse de forma de
778 poder ser reciclada. Esto implica que si esta celda almacena punteros, los
779 contadores de las celdas apuntadas deben ser decrementados también, porque
780 solo deben almacenarse en el contador las aristas del *live set* para
781 mantener la invariante. De esto puede resultar que otros contadores de
782 referencia queden en 0 y más celdas sean liberadas. Por lo tanto,
783 teóricamente la complejidad de eliminar una referencia puede ser
784 :math:`O(\lvert Live \thickspace set \rvert)` en el peor caso.
785
786 Las primitivas implementadas para este tipo de recolector son las
787 siguientes (acompañadas de una implementación básica)::
788
789    new()
790       cell = alloc()
791       if cell is null
792          throw out_of_memory
793       cell.rc = 1
794       return cell
795
796    del(cell)
797       cell.rc = cell.rc - 1
798       if cell.rc is 0
799          for child* in cell.children
800             del(*child)
801          free(cell)
802
803    update(ref*, cell)
804       cell.rc = cell.rc + 1
805       del(*ref)
806       *ref = cell
807
808
809 Ejemplo
810 ^^^^^^^
811
812 A continuación se presenta un ejemplo gráfico para facilitar la comprensión
813 del algoritmo.
814
815 Por simplicidad se asumen celdas de tamaño fijo con dos punteros, ``left``
816 y ``right`` (estructura clásica para representar un árbol binario) y se
817 muestra el contador de referencias abajo del nombre de cada celda. Se parte
818 con una pequeña estructura ya construída y se muestra primero lo que ocurre
819 al eliminar la referencia :math:`r0 \to h1`:
820
821 .. TODO: figure
822
823 .. raw:: latex
824
825    \begin{figure}[htp]
826    \centering
827    \subfigure[TODO]{
828
829 .. digraph:: g3_1
830
831    margin = 0;
832    ratio  = fill;
833    size   = "3.0,3.8";
834    edge [ color = gray40 ];
835    node [
836       shape     = record,
837       width     = 0,
838       height    = 0,
839       style     = filled,
840       fillcolor = gray25,
841       fontcolor = white
842    ];
843
844    subgraph cluster_all {
845
846       root [
847          label     = "root\nset|<r0> r0\n*|<r1> r1",
848          style     = filled,
849          fillcolor = gray96,
850          fontcolor = black,
851       ];
852
853       h1 [ label = "h1\n1|<l> left|<r> right" ];
854       h2 [ label = "h2\n2|<l> left|<r> right" ];
855       h3 [ label = "h3\n2|<l> left|<r> right" ];
856       h4 [ label = "h4\n1|<l> left|<r> right" ];
857       h5 [ label = "h5\n1|<l> left|<r> right" ];
858       h6 [ label = "h6\n1|<l> left|<r> right" ];
859
860       root:r0 -> h1 [ style = bold, color = black ];
861       root:r1 -> h3;
862       h1:l -> h2;
863       h1:r -> h3;
864       h2:l -> h4;
865       h2:r -> h5;
866       h3:l -> h2;
867       h3:r -> h6;
868
869    }
870
871 .. raw:: latex
872
873    }
874    \subfigure[TODO]{
875
876 .. digraph:: g3_2
877
878    margin = 0;
879    ratio  = fill;
880    size   = "3.0,3.8";
881    edge [ color = gray40 ];
882    node [
883       shape     = record,
884       width     = 0,
885       height    = 0,
886       style     = filled,
887       fillcolor = gray25,
888       fontcolor = white
889    ];
890
891    subgraph cluster_all {
892
893       root [
894          label     = "root\nset|<r0> r0\n*|<r1> r1",
895          style     = filled,
896          fillcolor = gray96,
897          fontcolor = black,
898       ];
899
900       subgraph marked {
901          node [ fillcolor = white, fontcolor = black ];
902          h1;
903       };
904
905       h1 [ label = "h1\n0|<l> left|<r> right" ];
906       h2 [ label = "h2\n2|<l> left|<r> right" ];
907       h3 [ label = "h3\n2|<l> left|<r> right" ];
908       h4 [ label = "h4\n1|<l> left|<r> right" ];
909       h5 [ label = "h5\n1|<l> left|<r> right" ];
910       h6 [ label = "h6\n1|<l> left|<r> right" ];
911
912       root:r0 -> h1 [ style = invis ];
913       root:r1 -> h3;
914       h1:l -> h2 [ style = bold, color = black ];
915       h1:r -> h3;
916       h2:l -> h4;
917       h2:r -> h5;
918       h3:l -> h2;
919       h3:r -> h6;
920
921    }
922
923 .. raw:: latex
924
925    }
926    \caption{TODO, part 1}
927    \end{figure}
928
929    \begin{figure}[htp]
930    \centering
931    \subfigure[TODO]{
932
933 .. digraph:: g3_3
934
935    margin = 0;
936    ratio  = fill;
937    size   = "3.0,3.8";
938    edge [ color = gray40 ];
939    node [
940       shape     = record,
941       width     = 0,
942       height    = 0,
943       style     = filled,
944       fillcolor = gray25,
945       fontcolor = white
946    ];
947
948    subgraph cluster_all {
949
950       root [
951          label     = "root\nset|<r0> r0\n*|<r1> r1",
952          style     = filled,
953          fillcolor = gray96,
954          fontcolor = black,
955       ];
956
957       subgraph marked {
958          node [ fillcolor = white, fontcolor = black ];
959          h1;
960       };
961
962       h1 [ label = "h1\n0|<l> left|<r> right" ];
963       h2 [ label = "h2\n1|<l> left|<r> right" ];
964       h3 [ label = "h3\n2|<l> left|<r> right" ];
965       h4 [ label = "h4\n1|<l> left|<r> right" ];
966       h5 [ label = "h5\n1|<l> left|<r> right" ];
967       h6 [ label = "h6\n1|<l> left|<r> right" ];
968
969       root:r0 -> h1 [ style = invis ];
970       root:r1 -> h3;
971       h1:l -> h2 [ style = invis ];
972       h1:r -> h3 [ style = bold, color = black ];
973       h2:l -> h4;
974       h2:r -> h5;
975       h3:l -> h2;
976       h3:r -> h6;
977
978    }
979
980 .. raw:: latex
981
982    }
983    \subfigure[TODO]{
984
985 .. digraph:: g3_4
986
987    margin = 0;
988    ratio  = fill;
989    size   = "3.0,3.8";
990    edge [ color = gray40 ];
991    node [
992       shape     = record,
993       width     = 0,
994       height    = 0,
995       style     = filled,
996       fillcolor = gray25,
997       fontcolor = white
998    ];
999
1000    subgraph cluster_all {
1001
1002       root [
1003          label     = "root\nset|<r0> r0|<r1> r1",
1004          style     = filled,
1005          fillcolor = gray96,
1006          fontcolor = black,
1007       ];
1008
1009       subgraph marked {
1010          node [ fillcolor = white, fontcolor = black ];
1011          h1;
1012       };
1013
1014       h1 [ label = "h1\n0|<l> left|<r> right" ];
1015       h2 [ label = "h2\n1|<l> left|<r> right" ];
1016       h3 [ label = "h3\n1|<l> left|<r> right" ];
1017       h4 [ label = "h4\n1|<l> left|<r> right" ];
1018       h5 [ label = "h5\n1|<l> left|<r> right" ];
1019       h6 [ label = "h6\n1|<l> left|<r> right" ];
1020
1021       root:r0 -> h1 [ style = invis ];
1022       root:r1 -> h3;
1023       h1:l -> h2 [ style = invis ];
1024       h1:r -> h3 [ style = invis ];
1025       h2:l -> h4;
1026       h2:r -> h5;
1027       h3:l -> h2;
1028       h3:r -> h6;
1029
1030    }
1031
1032 .. raw:: latex
1033
1034    }
1035    \caption{TODO, parte 2}
1036    \end{figure}
1037
1038 Como se observa, la celda ``h1`` queda con el contador en 0, por lo tanto
1039 pasa a ser *basura*. Los contadores de las celdas a las que apuntaban
1040 ``h1.left`` y ``h1.right`` son decrementados, pero no se detecta más basura
1041 porque sigue existiendo un camino del *root set* a aquellas celdas, y por
1042 transitividad a todas aquellas celdas apuntadas por éstas. Es por esto que
1043 no es necesario seguir recorriendo el grafo de conectividad.
1044
1045 A continuación se muestra como opera el algoritmo al cambiar a donde apunta
1046 ``h3.left``, haciéndola apuntar a ``h5``. Es decir, que pasa luego de la
1047 operación ``update(h3.left, h5)`` (por simplicidad no se muestra más la
1048 celda ``h1`` que ahora es *basura*):
1049
1050 .. TODO: figure
1051
1052 .. raw:: latex
1053
1054    \begin{figure}[htp]
1055    \centering
1056    \subfigure[TODO]{
1057
1058 .. digraph:: g4_1
1059
1060    margin = 0;
1061    ratio  = fill;
1062    size   = "3.0,3.8";
1063    edge [ color = gray40 ];
1064    node [
1065       shape     = record,
1066       width     = 0,
1067       height    = 0,
1068       style     = filled,
1069       fillcolor = gray25,
1070       fontcolor = white
1071    ];
1072
1073    subgraph cluster_all {
1074
1075       root [
1076          label     = "root\nset|<r0> r0|<r1> r1",
1077          style     = filled,
1078          fillcolor = gray96,
1079          fontcolor = black,
1080       ];
1081
1082       subgraph marked {
1083          node [ fillcolor = white, fontcolor = black ];
1084       };
1085
1086       h2 [ label = "h2\n1|<l> left|<r> right" ];
1087       h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
1088       h4 [ label = "h4\n1|<l> left|<r> right" ];
1089       h5 [ label = "h5\n1|<l> left|<r> right" ];
1090       h6 [ label = "h6\n1|<l> left|<r> right" ];
1091
1092       root:r1 -> h3;
1093       h2:l -> h4;
1094       h2:r -> h5;
1095       h3:l -> h2 [ style = bold, color = black ];
1096       h3:r -> h6;
1097
1098    }
1099
1100 .. raw:: latex
1101
1102    }
1103    \subfigure[TODO]{
1104
1105 .. digraph:: g4_2
1106
1107    margin = 0;
1108    ratio  = fill;
1109    size   = "3.0,3.8";
1110    edge [ color = gray40 ];
1111    node [
1112       shape     = record,
1113       width     = 0,
1114       height    = 0,
1115       style     = filled,
1116       fillcolor = gray25,
1117       fontcolor = white
1118    ];
1119
1120    subgraph cluster_all {
1121
1122       root [
1123          label     = "root\nset|<r0> r0|<r1> r1",
1124          style     = filled,
1125          fillcolor = gray96,
1126          fontcolor = black,
1127       ];
1128
1129       subgraph marked {
1130          node [ fillcolor = white, fontcolor = black ];
1131       };
1132
1133       h2 [ label = "h2\n1|<l> left|<r> right" ];
1134       h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
1135       h4 [ label = "h4\n1|<l> left|<r> right" ];
1136       h5 [ label = "h5\n2|<l> left|<r> right" ];
1137       h6 [ label = "h6\n1|<l> left|<r> right" ];
1138
1139       root:r1 -> h3;
1140       h2:l -> h4;
1141       h2:r -> h5;
1142       h3:l -> h2 [ style = bold, color = black ];
1143       h3:l -> h5 [ style = dotted, color = black ];
1144       h3:r -> h6;
1145
1146    }
1147
1148 .. raw:: latex
1149
1150    }
1151    \caption{TODO, part 1}
1152    \end{figure}
1153
1154    \begin{figure}[htp]
1155    \centering
1156    \subfigure[TODO]{
1157
1158 .. digraph:: g4_3
1159
1160    margin = 0;
1161    ratio  = fill;
1162    size   = "3.0,3.8";
1163    edge [ color = gray40 ];
1164    node [
1165       shape     = record,
1166       width     = 0,
1167       height    = 0,
1168       style     = filled,
1169       fillcolor = gray25,
1170       fontcolor = white
1171    ];
1172
1173    subgraph cluster_all {
1174
1175       root [
1176          label     = "root\nset|<r0> r0|<r1> r1",
1177          style     = filled,
1178          fillcolor = gray96,
1179          fontcolor = black,
1180       ];
1181
1182       subgraph marked {
1183          node [ fillcolor = white, fontcolor = black ];
1184          h2;
1185       };
1186
1187       h2 [ label = "h2\n0|<l> left|<r> right" ];
1188       h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
1189       h4 [ label = "h4\n1|<l> left|<r> right" ];
1190       h5 [ label = "h5\n2|<l> left|<r> right" ];
1191       h6 [ label = "h6\n1|<l> left|<r> right" ];
1192
1193       root:r1 -> h3;
1194       h2:l -> h4 [ style = bold, color = black ];
1195       h2:r -> h5;
1196       h3:l -> h2 [ style = invis ];
1197       h3:l -> h5 [ style = dotted, color = black ];
1198       h3:r -> h6;
1199
1200    }
1201
1202 .. raw:: latex
1203
1204    }
1205    \subfigure[TODO]{
1206
1207 .. digraph:: g4_4
1208
1209    margin = 0;
1210    ratio  = fill;
1211    size   = "3.0,3.8";
1212    edge [ color = gray40 ];
1213    node [
1214       shape     = record,
1215       width     = 0,
1216       height    = 0,
1217       style     = filled,
1218       fillcolor = gray25,
1219       fontcolor = white
1220    ];
1221
1222    subgraph cluster_all {
1223
1224       root [
1225          label     = "root\nset|<r0> r0|<r1> r1",
1226          style     = filled,
1227          fillcolor = gray96,
1228          fontcolor = black,
1229       ];
1230
1231       subgraph marked {
1232          node [ fillcolor = white, fontcolor = black ];
1233          h2; h4;
1234       };
1235
1236       h2 [ label = "h2\n0|<l> left|<r> right" ];
1237       h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
1238       h4 [ label = "h4\n0|<l> left|<r> right" ];
1239       h5 [ label = "h5\n2|<l> left|<r> right" ];
1240       h6 [ label = "h6\n1|<l> left|<r> right" ];
1241
1242       root:r1 -> h3;
1243       h2:l -> h4 [ style = invis ];
1244       h2:r -> h5 [ style = bold, color = black ];
1245       h3:l -> h2 [ style = invis ];
1246       h3:l -> h5 [ style = dotted, color = black ];
1247       h3:r -> h6;
1248
1249    }
1250
1251 .. raw:: latex
1252
1253    }
1254    \caption{TODO, part 2}
1255    \end{figure}
1256
1257    \begin{figure}[htp]
1258    \centering
1259    \subfigure[TODO]{
1260
1261 .. digraph:: g4_5
1262
1263    margin = 0;
1264    ratio  = fill;
1265    size   = "3.0,3.8";
1266    edge [ color = gray40 ];
1267    node [
1268       shape     = record,
1269       width     = 0,
1270       height    = 0,
1271       style     = filled,
1272       fillcolor = gray25,
1273       fontcolor = white
1274    ];
1275
1276    subgraph cluster_all {
1277
1278       root [
1279          label     = "root\nset|<r0> r0|<r1> r1",
1280          style     = filled,
1281          fillcolor = gray96,
1282          fontcolor = black,
1283       ];
1284
1285       subgraph marked {
1286          node [ fillcolor = white, fontcolor = black ];
1287          h2; h4;
1288       };
1289
1290       h2 [ label = "h2\n0|<l> left|<r> right" ];
1291       h3 [ label = "h3\n1|<l> left\n*|<r> right" ];
1292       h4 [ label = "h4\n0|<l> left|<r> right" ];
1293       h5 [ label = "h5\n1|<l> left|<r> right" ];
1294       h6 [ label = "h6\n1|<l> left|<r> right" ];
1295
1296       root:r1 -> h3;
1297       h2:l -> h4 [ style = invis ];
1298       h2:r -> h5 [ style = invis ];
1299       h3:l -> h5 [ style = bold, color = black ];
1300       h3:l -> h2 [ style = invis ];
1301       h3:r -> h6;
1302
1303    }
1304
1305 .. raw:: latex
1306
1307    }
1308    \subfigure[TODO]{
1309
1310 .. digraph:: g4_6
1311
1312    margin = 0;
1313    ratio  = fill;
1314    size   = "3.0,3.8";
1315    edge [ color = gray40 ];
1316    node [
1317       shape     = record,
1318       width     = 0,
1319       height    = 0,
1320       style     = filled,
1321       fillcolor = gray25,
1322       fontcolor = white
1323    ];
1324
1325    subgraph cluster_all {
1326
1327       root [
1328          label     = "root\nset|<r0> r0|<r1> r1",
1329          style     = filled,
1330          fillcolor = gray96,
1331          fontcolor = black,
1332       ];
1333
1334       subgraph marked {
1335          node [ fillcolor = white, fontcolor = black ];
1336          h2; h4;
1337       };
1338
1339       h2 [ label = "h2\n0|<l> left|<r> right" ];
1340       h3 [ label = "h3\n1|<l> left|<r> right" ];
1341       h4 [ label = "h4\n0|<l> left|<r> right" ];
1342       h5 [ label = "h5\n1|<l> left|<r> right" ];
1343       h6 [ label = "h6\n1|<l> left|<r> right" ];
1344
1345       root:r1 -> h3;
1346       h2:l -> h4 [ style = invis ];
1347       h2:r -> h5 [ style = invis ];
1348       h3:l -> h5;
1349       h3:l -> h2 [ style = invis ];
1350       h3:r -> h6;
1351
1352    }
1353
1354 .. raw:: latex
1355
1356    }
1357    \caption{TODO, parte 3}
1358    \end{figure}
1359
1360 .. _ref_gc_cycles:
1361
1362 TODO El problema de los ciclos
1363
1364
1365 Marcado y barrido
1366 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1367
1368 TODO
1369
1370
1371
1372 Copia/Semi-espacio
1373 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1374
1375 TODO
1376
1377
1378
1379 Compactado
1380 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1381
1382 TODO
1383
1384
1385
1386 Clasificación
1387 ----------------------------------------------------------------------------
1388
1389 La cantidad de clasificaciones que pueden hacerse respecto a algoritmos de
1390 recolección de basura son muy grandes. Muchas de estas clasificaciones se
1391 superponen entre sí, habiendo algoritmos que aplican muchas técnicas a la
1392 vez o recolectores híbridos que aplican una técnica para algún tipo de
1393 objeto y otra para otros.
1394
1395 A continuación se enumeran las clasificaciones más importantes que se
1396 pudieron observar en la investigación sobre el `estado del arte`_.
1397
1398 .. _ref_gc_direct:
1399
1400 Directa / indirecta
1401 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1402
1403 Generalmente se llama recolección **directa** a aquella en la cual el
1404 compilador o lenguaje instrumenta al *mutator* de forma tal que la
1405 información de conectividad se mantenga activamente cada vez que hay un
1406 cambio en él. Normalmente se utiliza un contador de referencia en cada
1407 celda para este propósito, permitiendo almacenar en todo momento la
1408 cantidad de nodos que apuntan a ésta (dejando de lado el :ref:`problema de
1409 los ciclos <ref_gc_cycles>`). Esto permite reclamar una celda
1410 instantáneamente cuando el *mutator* deja de hacer referencia a ella. Este
1411 tipo de recolectores son, inherentemente :ref:`incrementales <ref_gc_inc>`.
1412
1413 Por el contrario, los recolectores **indirectos** normalmente no
1414 interfieren con el *mutator* en cada actualización del grafo de
1415 conectividad (exceptuando algunos :ref:`recolectores incrementales
1416 <ref_gc_inc>` que a veces necesitan instrumentar el *mutator* pero no para
1417 mantener el estado del grafo de conectividad completo). La recolección se
1418 dispara usualmente cuando el *mutator* requiere alocar memoria pero no hay
1419 más memoria libre conocida disponible y el recolector se encarga de generar
1420 la información de conectividad desde cero para determinar qué celdas son
1421 *basura*.
1422
1423 Estas son las dos grandes familias de recolectores, también conocidos como
1424 `conteo de referencias`_ (directa) y *traicing garbage collection*
1425 (indirecta).
1426
1427
1428 .. _ref_gc_inc:
1429
1430 Incremental
1431 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1432
1433 Recolección incremental es aquella que se realiza de forma intercalada con
1434 el *mutator*. En general el propósito es disminuir el tiempo de las pausas
1435 causadas por el recolector (aunque generalmente el resultado es un mayor
1436 costo en tiempo total de recolección).
1437
1438 De los `algoritmos clásicos`_ el único que es incremental en su forma más
1439 básica es el `conteo de referencias`_. Otros recolectores pueden hacerse
1440 incrementales de diversas maneras, pero en general consta de hacer parte
1441 del trabajo de escanear el grafo de conectividad cada vez que el *mutator*
1442 aloca memoria. En general para hacer esto es también necesario instrumentar
1443 al *mutator* de forma tal que informe al recolector cada vez que cambia el
1444 grafo de conectividad, para que éste pueda marcar al sub-grafo afectado por
1445 el cambio como *desactualizado* y así re-escanearlo nuevamente en la
1446 próxima iteración.
1447
1448 En general la eficiencia de los recolectores incrementales disminuye
1449 considerablemente cuando el *mutator* actualiza muy seguido el grafo de
1450 conectividad, porque debe re-escanear sub-grafos que ya había escaneado una
1451 y otra vez. A esto se debe también que en general el tiempo de
1452 procesamiento total de un recolector incremental sea mayor que uno no
1453 incremental, aunque el tiempo de pausa de una recolección sea menor.
1454
1455
1456 .. _ref_gc_concurrent:
1457
1458 Concurrente / *stop-the-world*
1459 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1460
1461 Los recolectores concurrentes son aquellos que pueden correr en paralelo
1462 con el *mutator*. Por el contrario, aquellos que pausan el *mutator* para
1463 realizar la recolección son usualmente denominados *stop-the-world* (*parar
1464 el mundo*), haciendo referencia a que pausan todos los hilos del *mutator*
1465 para poder escanear el grafo de conectividad de forma consistente.
1466
1467 Para lograr que un recolector sea concurrente generalmente el mecanismo es
1468 similar al necesario para hacer un :ref:`recolector incremental
1469 <ref_gc_inc>`: hay que instrumentar al *mutator* para que informe al
1470 recolector cuando se realiza algún cambio en el grafo de conectividad, de
1471 forma tal que pueda volver a escanear el sub-grafo afectado por el cambio.
1472
1473 Esto también trae como consecuencia el incremento en el tiempo total que
1474 consume el recolector, debido a la necesidad de re-escanear sub-grafos que
1475 han sido modificados.
1476
1477 .. _ref_gc_art:
1478
1479 Estado del arte
1480 ----------------------------------------------------------------------------
1481
1482 .. explicar la cantidad de cosas que hay (que son muchas) y dar algunos
1483    ejemplos.
1484
1485 TODO
1486
1487 Cloning
1488
1489
1490 1. Instrumentar el *mutator* de forma tal de que informe al recolector cada
1491    vez que cambia el grafo de conectividad, de manera que pueda re-escanear
1492    el sub-grafo que afectado por el cambio.
1493
1494 2. Tomar una foto de la memoria y escanear esa foto estática en vez de la
1495    memoria original, de forma que cualquier cambio en del *mutator* no
1496    afecte la vista de la memoria del recolector.
1497
1498 Ambos métodos tienen ventajas y desventajas. El primero no necesita hacer
1499 una copia costosa de la memoria, pero existe la posibilidad de que el
1500 recolector nunca pueda escanear el grafo de conectividad completo, si el
1501 *mutator* modifica el grafo más rápido de lo que el recolector lo escanea.
1502 Si bien hay formas de evitar esto, es usual que el trabajo de recolección
1503 se vea considerablemente incrementado por la cantidad de veces que hay que
1504 re-escanear el grafo. El segundo método puede ser costoso por las copias
1505 necesarias (aunque esto puede ser mitigado empleando alguna forma de *COW*
1506 [#gccow]_) y existe la posibilidad de que no se recuperen celdas que el
1507 *mutator*
1508
1509
1510 .. [#gccow] *COW* (del inglés *Copy On Write* o *copiar al escribir*) es
1511    una técnica muy utilizada para disminuir las copias innecesarias,
1512    evitando hacer la copia hasta que haya una modificación. Mientras no
1513    hayan modificaciones no es necesario realizar una copia porque todos los
1514    interesados verán la misma información. Esta técnica es utilizada por el
1515    *kernel* de Linux_ por ejemplo, para que varias instancias de un mismo
1516    proceso puedan compartir la memoria.
1517
1518
1519 Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative
1520 Environment", Software Practice & Experience, September 1988, pp. 807-820.
1521 http://www.hpl.hp.com/personal/Hans_Boehm/spe_gc_paper/preprint.pdf
1522 (http://www.hpl.hp.com/personal/Hans_Boehm/spe_gc_paper/)
1523
1524 Boehm, H., "Space Efficient Conservative Garbage Collection", Proceedings
1525 of the ACM SIGPLAN '93 Conference on Programming Language Design and
1526 Implementation, SIGPLAN Notices 28, 6 (June 1993), pp. 197-206.
1527 http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi93.ps.Z
1528
1529 Boehm, H., A. Demers, and S. Shenker, "Mostly Parallel Garbage Collection",
1530 Proceedings of the ACM SIGPLAN '91 Conference on Programming Language
1531 Design and Implementation, SIGPLAN Notices 26, 6 (June 1991), pp. 157-164.
1532 http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi91.ps.Z
1533
1534 Implementación de Bohem GC
1535 http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcdescr.html
1536
1537 Interfaz de Bohem GC
1538 http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html
1539
1540
1541 .. include:: links.rst
1542
1543 .. vim: set ts=3 sts=3 sw=3 et tw=75 :