-.. _ref_gc_copy_2space:
+.. _ref_gc_copy:
Copia de semi-espacio
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Este algoritmo consiste en hacer una partición del *heap* en 2 mitades
o *semi-espacios*, llamados usualmente *Fromspace* y *Tospace*. El primero se
utiliza para alocar nuevas celdas de forma lineal, asumiendo un *heap*
-contiguo, incrementando un puntero (ver figura :vref:`fig:gc-copy-2space`).
-Esto se conoce como *pointer bump allocation* y es, probablemente, la forma
-más eficiente de alocar memoria (tan eficiente como alocar memoria en el
-*stack*).
+contiguo, incrementando un puntero (ver figura :vref:`fig:gc-copy`). Esto se
+conoce como *pointer bump allocation* y es, probablemente, la forma más
+eficiente de alocar memoria (tan eficiente como alocar memoria en el *stack*).
-.. fig:: fig:gc-copy-2space
+.. fig:: fig:gc-copy
Estructura del *heap* de un recolector con copia de semi-espacios.
/| /| BB "Tospace"
-La segunda mitad (*Tospace*) permanece ociosa hasta que se agota el espacio en
-el *Fromspace*; en ese momento comienza el proceso de recolección de basura
-que consiste en recorrer el grafo de conectividad, copiando las celdas *vivas*
-del *Fromspace* al *Tospace* de manera contigua, como si estuvieran alocando
-por primera vez. Como la posición en memoria de las celdas cambia al ser
-movidas, es necesario actualizar la dirección de memoria de todas las celdas
-*vivas*. Para esto se almacena una dirección de memoria de redirección,
-*forwarding address*, en las celdas que mueven. La *forwarding address* sirve
-a su vez de marca, para no recorrer una celda dos veces (como se explica en
-:ref:`ref_gc_intro_mark`). Cuando se encuentra una celda que ya fue movida,
-simplemente se actualiza la referencia por la cual se llegó a esa celda para
-que apunte a la nueva dirección, almacenada en la *forwarding address*. Una
-vez finalizado este proceso, el *Fromspace* y *Tospace* invierten roles y se
-prosigue de la misma manera (todo lo que quedó en el viejo *Fromspace* es
-*basura* por definición, por lo que se convierte el *Tospace*).
+La segunda mitad (*Tospace*) permanece inutilizada hasta que se agota el
+espacio en el *Fromspace*; en ese momento comienza el proceso de recolección
+de basura que consiste en recorrer el grafo de conectividad, copiando las
+celdas *vivas* del *Fromspace* al *Tospace* de manera contigua, como si
+estuvieran alocando por primera vez. Como la posición en memoria de las celdas
+cambia al ser movidas, es necesario actualizar la dirección de memoria de
+todas las celdas *vivas*. Para esto se almacena una dirección de memoria de
+redirección, *forwarding address*, en las celdas que mueven. La *forwarding
+address* sirve a su vez de marca, para no recorrer una celda dos veces (como
+se explica en :ref:`ref_gc_intro_mark`). Cuando se encuentra una celda que ya
+fue movida, simplemente se actualiza la referencia por la cual se llegó a esa
+celda para que apunte a la nueva dirección, almacenada en la *forwarding
+address*. Una vez finalizado este proceso, el *Fromspace* y *Tospace*
+invierten roles y se prosigue de la misma manera (todo lo que quedó en el
+viejo *Fromspace* es *basura* por definición, por lo que se convierte el
+*Tospace*).
A continuación se presenta una implementación sencilla de los servicios
provistos por este tipo de recolectores. Cabe destacar que este tipo de
| |
| |
| |
- | /-----------+"root set" |
+ | /---+"root set" |
| | |
| | h3 h2 h1 h4 |
| V______________________________________________ |
| HHHHHHHHhhhhhhhhHHHHHHHHhhhhhhhhBBBBBBBBBBBBBBBB |
| ~~|~~~~~~A~|~A~~|~A~|~~~~~~A~~~A~~~~~~~~~~~~~~ |
| | | | | | | | | | |
- | \------/ | \--/ | \------/ \----+"free" |
+ | \------/ | \--/ | \------/ \---+"free" |
| "Fromspace" \------/ |
+--------------------------------------------------+