start_the_world()
La variable **global** ``more_to_scan`` indica al algoritmo iterativo cuando
-debe finalizar: la función ``mark()`` (que veremos más adelante) lo pone en
-``true`` cuando una nueva celda debe ser visitada, por lo tanto la iteración
-se interrumpe cuando no hay más celdas por visitar.
+debe finalizar: la función ``mark_range()`` (que veremos más adelante) lo pone
+en ``true`` cuando una nueva celda debe ser visitada, por lo tanto la
+iteración se interrumpe cuando no hay más celdas por visitar.
Las funciones ``stop_the_world()`` y ``start_the_world()`` sencillamente
pausan y reanudan todos los hilos respectivamente::
<gc_conserv>` (es decir, tomando cada *word* como si fuera un puntero)::
function mark_static_data() is
- foreach word in static_data
- pointer = cast(void*) word
- mark(pointer)
+ mark_range(static_data.begin, static_data.end)
Para poder tomar los registros como parte del *root set* primero se apilan
en el *stack* a través de la función::
function mark_stacks() is
foreach thread in threads
- foreach word in thread.stack
- pointer = cast(void*) word
- mark(pointer)
+ mark_range(thread.stack.begin, thread.stack.end)
Dado que D_ soporta manejo de memoria manual al mismo tiempo que memoria
automática, es posible que existan celdas de memoria que no estén en el *root
completo se procede a marcar las raíces definidas por el usuario::
function mark_user_roots() is
- foreach pointer in user_roots
- mark(pointer)
+ foreach root_range in user_roots
+ mark_range(root_range.begin, root_range.end)
El algoritmo de marcado no es recursivo sino iterativo por lo tanto al marcar
una celda (o bloque) no se siguen sus *hijas*, solo se activa el bit de *scan*
(a menos que la celda no contenga punteros, es decir, tenga el bit *noscan*)::
- function mark(pointer) is
- [pool, page, block] = find_block(pointer)
- if block is not null and block.mark is false
- block.mark = true
- if block.noscan is false
- block.scan = true
- global more_to_scan = true
+ function mark_range(begin, end) is
+ pointer = begin
+ while pointer < end
+ [pool, page, block] = find_block(pointer)
+ if block is not null and block.mark is false
+ block.mark = true
+ if block.noscan is false
+ block.scan = true
+ global more_to_scan = true
+ pointer++
Por lo tanto en este punto, tenemos todas las celdas inmediatamente
alcanzables desde el *root set* marcadas y con el bit *scan* activado si la
if block.scan is true
block.scan = false
if page.block_size is PAGE // objeto grande
- start = cast(byte*) page
+ begin = cast(byte*) page
end = find_big_object_end(pool, page)
- foreach word in start..end
- pointer = cast(void*) word
- mark(pointer)
+ mark_range(begin, end)
else // objeto pequeño
- foreach word in block
- pointer = cast(void*) word
- mark(pointer)
+ mark_range(block.begin, block.end)
Aquí puede verse, con un poco de esfuerzo, la utilización de la
:ref:`abstracción tricolor <gc_intro_tricolor>`: todas las celdas alcanzables
Recolección
*mark(pbot, ptop)*
- marca un rango de memoria. Este método es análogo al ``mark()``
- presentado en la sección :ref:`dgc_algo_mark` pero marca un rango
- completo de memoria, lo que permite que sea considerablemente más
- eficiente.
+ marca un rango de memoria. Este método es análogo al ``mark_range()``
+ presentado en la sección :ref:`dgc_algo_mark`.
*fullcollectshell()*
guarda los registros en el *stack* y llama a ``fullcollect()``. El