% Generated by Sphinx.
\documentclass[a4paper,11pt,spanish]{manual}
\usepackage[utf8]{inputenc}
\usepackage[T1]{fontenc}
\usepackage{babel}
\usepackage{times}
\usepackage[Sonny]{fncychap}
\usepackage{longtable}
\usepackage[final]{varioref} \usepackage{sphinx}

\usepackage{epigraph}
\usepackage{subfig}

% Se hackea el Makefile para hacer el usepackage de varioref antes del
% usepackage{sphinx} porque si se lo hace despues se rompe el indice del PDF
% (en realidad tiene que estar antes del usepackage del hyperref, que se carga
% en el paquete sphinx). Para cambiar entre draft/final hay que modificar el
% Makefile.
%\usepackage[final]{varioref} % XXX: breaks PDF index, use [final] when done

% Relaja restricciones de LaTeX para floats, ver:
% http://mintaka.sdsu.edu/GF/bibliog/latex/floats.html
% http://www.tex.ac.uk/cgi-bin/texfaq2html?label=floats
\renewcommand{\topfraction}{.7}
\renewcommand{\bottomfraction}{.7}
\renewcommand{\textfraction}{.05}
\renewcommand{\floatpagefraction}{.7}
\setcounter{topnumber}{1}
\setcounter{bottomnumber}{1}
\setcounter{totalnumber}{4}

% Profundida maxima de tabla de contenidos
\setcounter{tocdepth}{2}

% Color de fondo de codigo
\definecolor{VerbatimColor}{rgb}{0.95,0.95,0.95}
\definecolor{VerbatimBorderColor}{rgb}{0.75,0.75,0.75}

% Definiciones para PDF
\hypersetup{
	pdftitle={Recolecci\'on de basura en D},
	pdfauthor={Leandro Mat\'ias Lucarella},
	pdfsubject={Tesis de Ingenier\'ia en Inform\'atica, FIUBA},
	pdfkeywords={gc}{d}{cdgc}{fork}{concurrent}
}


\title{Recolección de basura en D}
\date{Octubre 2010}
\release{1.0}
\author{Leandro Matías Lucarella}
\newcommand{\sphinxlogo}{}
\renewcommand{\releasename}{Release}
\makeindex


\makeatletter
\def\PYG@reset{\let\PYG@it=\relax \let\PYG@bf=\relax%
    \let\PYG@ul=\relax \let\PYG@tc=\relax%
    \let\PYG@bc=\relax \let\PYG@ff=\relax}
\def\PYG@tok#1{\csname PYG@tok@#1\endcsname}
\def\PYG@toks#1+{\ifx\relax#1\empty\else%
    \PYG@tok{#1}\expandafter\PYG@toks\fi}
\def\PYG@do#1{\PYG@bc{\PYG@tc{\PYG@ul{%
    \PYG@it{\PYG@bf{\PYG@ff{#1}}}}}}}
\def\PYG#1#2{\PYG@reset\PYG@toks#1+\relax+\PYG@do{#2}}

\def\PYG@tok@gd{\def\PYG@tc##1{\textcolor[rgb]{0.63,0.00,0.00}{##1}}}
\def\PYG@tok@gu{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.50,0.00,0.50}{##1}}}
\def\PYG@tok@gt{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.25,0.82}{##1}}}
\def\PYG@tok@gs{\let\PYG@bf=\textbf}
\def\PYG@tok@gr{\def\PYG@tc##1{\textcolor[rgb]{1.00,0.00,0.00}{##1}}}
\def\PYG@tok@cm{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}}
\def\PYG@tok@vg{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
\def\PYG@tok@m{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
\def\PYG@tok@mh{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
\def\PYG@tok@cs{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}\def\PYG@bc##1{\colorbox[rgb]{1.00,0.94,0.94}{##1}}}
\def\PYG@tok@ge{\let\PYG@it=\textit}
\def\PYG@tok@vc{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
\def\PYG@tok@il{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
\def\PYG@tok@go{\def\PYG@tc##1{\textcolor[rgb]{0.19,0.19,0.19}{##1}}}
\def\PYG@tok@cp{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@gi{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.63,0.00}{##1}}}
\def\PYG@tok@gh{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.00,0.50}{##1}}}
\def\PYG@tok@ni{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.84,0.33,0.22}{##1}}}
\def\PYG@tok@nl{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.13,0.44}{##1}}}
\def\PYG@tok@nn{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}}
\def\PYG@tok@no{\def\PYG@tc##1{\textcolor[rgb]{0.38,0.68,0.84}{##1}}}
\def\PYG@tok@na{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@nb{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@nc{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.05,0.52,0.71}{##1}}}
\def\PYG@tok@nd{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.33,0.33,0.33}{##1}}}
\def\PYG@tok@ne{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@nf{\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.49}{##1}}}
\def\PYG@tok@si{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.44,0.63,0.82}{##1}}}
\def\PYG@tok@s2{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@vi{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
\def\PYG@tok@nt{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.02,0.16,0.45}{##1}}}
\def\PYG@tok@nv{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.38,0.84}{##1}}}
\def\PYG@tok@s1{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@gp{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}}
\def\PYG@tok@sh{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@ow{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@sx{\def\PYG@tc##1{\textcolor[rgb]{0.78,0.36,0.04}{##1}}}
\def\PYG@tok@bp{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@c1{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}}
\def\PYG@tok@kc{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@c{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.50,0.56}{##1}}}
\def\PYG@tok@mf{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
\def\PYG@tok@err{\def\PYG@bc##1{\fcolorbox[rgb]{1.00,0.00,0.00}{1,1,1}{##1}}}
\def\PYG@tok@kd{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@ss{\def\PYG@tc##1{\textcolor[rgb]{0.32,0.47,0.09}{##1}}}
\def\PYG@tok@sr{\def\PYG@tc##1{\textcolor[rgb]{0.14,0.33,0.53}{##1}}}
\def\PYG@tok@mo{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
\def\PYG@tok@mi{\def\PYG@tc##1{\textcolor[rgb]{0.13,0.50,0.31}{##1}}}
\def\PYG@tok@kn{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@o{\def\PYG@tc##1{\textcolor[rgb]{0.40,0.40,0.40}{##1}}}
\def\PYG@tok@kr{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@s{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@kp{\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@w{\def\PYG@tc##1{\textcolor[rgb]{0.73,0.73,0.73}{##1}}}
\def\PYG@tok@kt{\def\PYG@tc##1{\textcolor[rgb]{0.56,0.13,0.00}{##1}}}
\def\PYG@tok@sc{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@sb{\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@k{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.00,0.44,0.13}{##1}}}
\def\PYG@tok@se{\let\PYG@bf=\textbf\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}
\def\PYG@tok@sd{\let\PYG@it=\textit\def\PYG@tc##1{\textcolor[rgb]{0.25,0.44,0.63}{##1}}}

\def\PYGZbs{\char`\\}
\def\PYGZus{\char`\_}
\def\PYGZob{\char`\{}
\def\PYGZcb{\char`\}}
\def\PYGZca{\char`\^}
% for compatibility with earlier versions
\def\PYGZat{@}
\def\PYGZlb{[}
\def\PYGZrb{]}
\makeatother

\begin{document}
\shorthandoff{"}
\maketitle
\tableofcontents
\hypertarget{--doc-index}{}
\resetcurrentobjects
\hypertarget{--doc-referencias}{}
\resetcurrentobjects
\hypertarget{--doc-links}{}\pagestyle{plain}
\pagenumbering{roman}
\setcounter{page}{3}
\listoffigures
\listoftables
\newpage
\resetcurrentobjects
\hypertarget{--doc-resumen}{}

\hypertarget{resumen}{}\pagestyle{empty}
\section*{Resumen}
El manejo de memoria es un problema recurrente en los lenguajes de
programación; dada su complejidad es muy propenso a errores y las
consecuencias de dichos errores pueden ser muy graves. La \emph{recolección de
basura} es el área de investigación que trata las técnicas de manejo
automático de memoria. \href{http://www.digitalmars.com/d/}{D} es un lenguaje de programación compilado, con tipado
estático y multi-paradigma que combina el poder de lenguajes de programación
de bajo nivel, como C, con la facilidad de los de alto nivel, como \href{http://www.python.org/}{Python}
o \href{http://www.java.com/}{Java}. \href{http://www.digitalmars.com/d/}{D} provee recolección de basura pero ha sido frecuentemente criticada
por sus varias falencias. Dadas las particularidades del lenguaje, plantea un
desafío casi único en cuanto al diseño de un recolector.

Este trabajo hace un recorrido por el estado del arte en recolección de basura
teniendo en cuenta los requerimientos de \href{http://www.digitalmars.com/d/}{D}; analiza la implementación del
recolector actual y propone mejoras con el objetivo principal de minimizar los
tiempos de pausa. Finalmente se construye un banco de pruebas para verificar
los resultados, que muestran una disminución de hasta 200 veces en el tiempo
de pausa del recolector y de hasta 3 veces en el tiempo total de ejecución.
\vfill
\section*{Agradecimientos}
A mis viejos y hermanos por soportarme y apoyarme, a Ali por estar siempre
para darme un empujoncito cuando me estanco, a Rosita por introducirme en el
tema, aguantar mis baches y ayudarme a mantener el foco, a Albertito por los
aportes técnicos invaluables a cambio de helado, a la gente que hizo la
innumerable cantidad de Software Libre que usé en este trabajo por
simplificarme enormemente la vida, y a la gente que me estoy olvidando por
hacer eso que me estoy olvidando que hizo.
\vspace{1in}
\epigraph{¡Es basura! ¡Es basura! ¡Es basura!}{Jay Sherman}

\clearpage
\setcounter{page}{1}
\pagenumbering{arabic}
\pagestyle{normal}
\resetcurrentobjects
\hypertarget{--doc-intro}{}

\hypertarget{intro}{}\chapter{Introducción}

La recolección de basura es una técnica que data de fines de los años `50,
cuando \href{http://en.wikipedia.org/wiki/John\_McCarthy\_\%28computer\_scientist\%29}{John McCarthy}, creador de \href{http://www.lisp.org/}{Lisp}, agregó a dicho lenguaje la
capacidad de administrar la memoria automáticamente (utilizando conteo de
referencias), entre muchos otros conceptos revolucionarios para la época que
recién fueron explotados masivamente en lenguajes dinámicos más modernos como
\href{http://www.perl.org/}{Perl}, \href{http://www.python.org/}{Python}, \href{http://www.ruby-lang.org/}{Ruby}, etc. A partir de este momento, muchos lenguajes tomaron
esta característica y hubo una gran cantidad de investigación al respecto,
tomando particular importancia.

Nuevos algoritmos fueron desarrollados para atacar distintos problemas
particulares y para mejorar el rendimiento, que ha sido una inquietud
incesante en la investigación de recolectores de basura. Sin embargo el
lenguaje más masivo que ha adoptado un recolector de basura (al menos en el
ámbito empresarial) fue \href{http://www.java.com/}{Java}, con el cual la investigación sobre recolección
de basura tomó un impulso extra. Probablemente el mayor desarrollo
e investigación en cuanto a recolección de basura se siga dando para \href{http://www.java.com/}{Java},
acotando tal vez un poco el alcance de estos avances dado que ese lenguaje
tiene características muy particulares (\emph{tipado} estático, corre sobre una
máquina virtual muy rica en cuanto a información de tipos, etc.) no
disponibles en otros lenguajes. Sin embargo los lenguajes funcionales y/o con
\emph{tipado} dinámico siguieron teniendo un nivel de investigación y desarrollo
importante, dado que fueron concebidos en su mayoría con la recolección de
basura como parte del diseño.

Probablemente los lenguajes en los cuales es más difícil aplicar los avances
que se desprendieron de \href{http://www.java.com/}{Java} o de las otras categorías de lenguajes con más
avances en recolección de basura sean los de más bajo nivel, como C y C++, en
los cuales se da lo inverso en cuanto a disponibilidad de información en
tiempo de ejecución, sumado a la permisividad de estos lenguajes para realizar
manipulación de memoria directamente y trabajar a muy bajo nivel. De la mano
de estos lenguajes apareció otra veta de investigación en lo que se denominó
recolectores de basura \emph{conservativos}.

Una categoría de lenguaje que ha quedado prácticamente vacante es un término
intermedio entre los lenguajes de muy alto nivel (como \href{http://www.java.com/}{Java}, \href{http://www.python.org/}{Python},
\href{http://www.haskell.org/}{Haskell}, etc.) y los de muy bajo nivel (como C y C++). El lenguaje de
programación \href{http://www.digitalmars.com/d/}{D} está en esta categoría y, a pesar de haber sido diseñado con
soporte de recolección de basura, al ser un lenguaje relativamente nuevo, ha
tenido muy poco desarrollo en ese área. El lenguaje tiene todas las
limitaciones de lenguajes de bajo nivel como C y C++, pero esas limitaciones
suelen estar más aisladas, y provee un poco más de información que puede ser
aprovechada por un recolector de la que suelen proveer los demás lenguajes de
estas características. Esto presenta una oportunidad única en cuanto
a investigación y desarrollo de recolectores que se ajusten a estas
características.


\section{Objetivo}

El objetivos de esta tesis es mejorar el recolector de basura de el lenguaje
\href{http://www.digitalmars.com/d/}{D}, investigando el estado del arte en recolección de basura y haciendo un
análisis de viabilidad de los algoritmos principales para optar por el que
mejor se ajuste a \href{http://www.digitalmars.com/d/}{D}. Una vez hecho esto se propone implementar una solución
y verificar los resultados mediante pruebas experimentales.

Un aspecto importante del análisis y la solución propuesta por este trabajo es
participar de la comunidad del lenguaje para poder desarrollar una mejora que
sea aceptada y utilizada por dicha comunidad. Por lo tanto el algoritmo
o mejora que ``mejor se ajuste a \href{http://www.digitalmars.com/d/}{D}'' estará supeditado en gran parte a los
requerimientos más urgentes de sus usuarios.


\section{Alcance}

El alcance de este trabajo se limita a los siguientes puntos:
\begin{itemize}
\item {} 
Explorar los problemas del recolector de basura actual.

\item {} 
Evaluar cuáles de estos problemas son de mayor importancia para la
comunidad de usuarios de \href{http://www.digitalmars.com/d/}{D}.

\item {} 
Analizar la viabilidad de algoritmos y optimizaciones para solucionar
o minimizar el o los problemas de mayor importancia.

\item {} 
Implementar una solución o mejora en base al análisis elaborado.

\item {} 
Comparar mediante la utilización de un banco de pruebas (\emph{benchmark}) la
implementación con la actual y posiblemente con otras implementaciones
relevantes a fin de cuantificarla.

\item {} 
Proveer todos los elementos necesarios para que la solución pueda ser
adoptada por el lenguaje.

\end{itemize}


\section{Limitaciones}

Dado que el lenguaje de programación \href{http://www.digitalmars.com/d/}{D} puede ser enlazado con código objeto
C, y por lo tanto interactuar directamente con éste, podrán haber limitaciones
en el recolector resultante con respecto a esto. En este trabajo se busca
lograr un recolector que sea eficiente para casos en donde el código que
interactúa con C esté bien aislado, por lo que estas porciones de código
pueden quedar por fuera del recolector de basura o necesitar un manejo
especial.


\section{Organización}

Este trabajo se encuentra dividido en 6 capítulos que se describen
a continuación:
\begin{enumerate}
\item {} 
\hyperlink{intro}{\emph{Introducción}}: breve descripción del problema a tratar, presentando
los objetivos y alcances del trabajo.

\item {} 
\hyperlink{d-lang}{\emph{El lenguaje de programación D}}: presenta las características principales del lenguaje,
destacando aquellas de mayor relevancia para este trabajo.

\item {} 
\hyperlink{gc}{\emph{Recolección de basura}}: presenta los algoritmos básicos de recolección de basura
y describe el estado del arte.

\item {} 
\hyperlink{dgc}{\emph{Recolección de basura en D}}: explica los problemas particulares que presenta el
lenguaje para la recolección de basura, describe el diseño
e implementación del recolector actual, presenta sus principales
deficiencias y analiza la viabilidad de diferentes soluciones.

\item {} 
\hyperlink{solucion}{\emph{Solución adoptada}}: propone una solución a los problemas principales
encontrados y define un banco de pruebas para analizar los resultados de
las modificaciones hechas.

\item {} 
\hyperlink{conclusion}{\emph{Conclusión}}: describe las conclusiones alcanzadas en base a los
resultados del trabajo, analizando puntos pendientes, mostrando trabajos
relacionados y proponiendo trabajos futuros.

\end{enumerate}

\resetcurrentobjects
\hypertarget{--doc-d}{}

\hypertarget{d-lang}{}\chapter{El lenguaje de programación D}


\section{Historia}

\href{http://www.digitalmars.com/d/}{D} es un lenguaje de programación relativamente joven. Nació en 1999 y el
2 de enero de 2007 salió su \href{http://www.digitalmars.com/d/1.0/changelog.html}{versión 1.0}. Poco tiempo después se continúo
el desarrollo del lenguaje en la \href{http://www.digitalmars.com/d/2.0/changelog.html}{versión 2.0}, que pasó a ser considerada
estable aproximadamente en junio de 2010 con el lanzamiento del libro ``The
D Programming Language'' \hyperlink{alx10}{{[}ALX10{]}}, pero aún es un trabajo en progreso.

El lenguaje fue diseñado e implementado por \href{http://www.walterbright.com/}{Walter Bright}, desarrollador
principal de Zortech C++, uno de los primeros compiladores de C++ que
compilaba a código nativo, y está fuertemente influenciado por éste. Sin
embargo toma muchos conceptos de otros lenguajes de más alto nivel, como \href{http://www.java.com/}{Java}
o incluso lenguajes dinámicos como \href{http://www.perl.org/}{Perl}, \href{http://www.python.org/}{Python} y \href{http://www.ruby-lang.org/}{Ruby}.

El origen del lenguaje está plasmado en su sitio web, en donde se cita
\hyperlink{dweb}{{[}DWEB{]}}:
\begin{quote}

It seems to me that most of the ``new'' programming languages fall into one
of two categories: Those from academia with radical new paradigms and those
from large corporations with a focus on RAD and the web. Maybe it's time
for a new language born out of practical experience implementing compilers.
\end{quote}

Esto podría traducirse como:
\begin{quote}

Parece que la mayoría de los lenguajes de programación ``nuevos'' caen en
2 categorías: aquellos académicos con nuevos paradigmas radicales
y aquellos de grandes corporaciones con el foco en el desarrollo rápido
y web. Tal vez es hora de que nazca un nuevo lenguaje de la experiencia
práctica implementando compiladores.
\end{quote}

La versión 1.0 fue más bien una etiqueta arbitraria que un indicador real de
estabilidad y completitud. Luego de liberarse se siguieron agregando nuevas
características al lenguaje hasta que se empezó el desarrollo en paralelo de
la versión 2.0 al introducirse el concepto de inmutabilidad y funciones
\emph{puras} \footnote{
Por funciones \emph{puras} en \href{http://www.digitalmars.com/d/}{D} se entiende que no tienen efectos
colaterales. Es decir, una función pura siempre que se llame con la misma
entrada producirá el mismo resultado. Esto es análogo a como funcionan los
lenguajes funcionales en general, abriendo la puerta a la programación de
estilo funcional en \href{http://www.digitalmars.com/d/}{D}.
} (a mediados de 2007).

A partir de este momento la versión 1.0 quedó \emph{teóricamente} congelada,
introduciendo solo cambios que arreglen errores (\emph{bug fixes}), agregando
nuevas características solamente en la versión 2.0 del lenguaje. La realidad
es que se hicieron cambios incompatibles a la versión 1.0 del lenguaje en
reiteradas ocasiones, pero se fue tendiendo a cada vez introducir menos
cambios incompatibles. Sin embargo al día de hoy el compilador de referencia
sigue teniendo algunas características presentes en la especificación del
lenguaje sin implementar, por lo que todavía no hay una implementación
completa de la versión 1.0 del lenguaje.

El lenguaje ha sido, hasta el desarrollo de la versión 2.0 al menos, un
esfuerzo unipersonal de \href{http://www.walterbright.com/}{Walter Bright}, dados sus problemas a la hora de
delegar o aceptar contribuciones. Esto motivó a la comunidad de usuarios de \href{http://www.digitalmars.com/d/}{D}
a crear bibliotecas base alternativas a la estándar (llamada \href{http://www.dsource.org/projects/phobos}{Phobos}) en las
cuales se pudiera trabajar sin las trabas impuestas por el autor del lenguaje.

En este contexto nacen primero \href{http://www.dsource.org/projects/mango}{Mango} y luego \href{http://www.dsource.org/projects/ares}{Ares}. \href{http://www.dsource.org/projects/mango}{Mango} fue creada por
Kris Macleod Bell a principios de 2004 como una biblioteca que provee
servicios básicos de entrada/salida (o \emph{I/O} de \emph{input/output} en inglés) de
alto rendimiento.   Siendo estos servicios algo básico lo más natural hubiera
sido que se encuentren en la biblioteca estándar de \href{http://www.digitalmars.com/d/}{D} pero por las
dificultades para contribuir a ésta, se desarrolla como una biblioteca
separada.   A mediados de 2004 Sean Kelly crea \href{http://www.dsource.org/projects/ares}{Ares} , con las mismas
motivaciones pero con la intención de crear una biblioteca base (conocida en
inglés como \emph{runtime}) que incluye los servicios básicos que necesita el
lenguaje (información de tipos, manejo de excepciones e hilos, creación
y manipulación de objetos, recolector de basura, etc.). Al poco tiempo de
liberarse \href{http://www.dsource.org/projects/ares}{Ares}, \href{http://www.dsource.org/projects/mango}{Mango} empieza a utilizarla como biblioteca base.

Para comienzos de 2006, se empieza a trabajar en la combinación de ambas
bibliotecas para lograr una biblioteca estándar alternativa con un alto grado
de cohesión. Finalmente a principios de 2007, coincidiendo por casualidad con
la aparición de \href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0}, se anuncia el resultado de este combinación bajo el
nombre de \href{http://www.dsource.org/projects/tango}{Tango}, proveyendo una alternativa completa y madura a la biblioteca
estándar de \href{http://www.digitalmars.com/d/}{D} \href{http://www.dsource.org/projects/phobos}{Phobos}.  A principios de 2008 los principales desarrolladores
de \href{http://www.dsource.org/projects/tango}{Tango} (Kris Bell, Sean Kelly, Lars Ivar Igesund y Michael Parker) publican
el libro llamado \href{http://www.dsource.org/projects/tango/wiki/LearnToTangoWithD}{Learn to Tango with D} \hyperlink{bkip08}{{[}BKIP08{]}}.

Esto por un lado fue un gran avance porque dio un impulso muy considerable al
lenguaje pero por otro un gran retroceso, porque todavía al día de hoy \href{http://www.digitalmars.com/d/1.0/changelog.html}{D
1.0} tiene dos bibliotecas base, una estándar pero de peor calidad, menos
mantenida y usada; y una alternativa de mayor calidad y apertura a la
comunidad (pero no estándar). El peor problema es que ambas son
\textbf{incompatibles}, por lo que un programa hecho con \href{http://www.dsource.org/projects/tango}{Tango} no funciona con
\href{http://www.dsource.org/projects/phobos}{Phobos} y viceversa (a menos que el programador haya invertido una cantidad de
tiempo considerable en asegurarse que funcione con ambas).

Esto hace que la compatibilidad de programas y bibliotecas esté muy
fragmentada entre las dos bibliotecas base. Si bien no parece que vaya a haber
solución alguna a este problema para \href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0}, \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0} va en camino
a solucionar este problema ya que utiliza \href{http://www.dsource.org/projects/druntime}{DRuntime}, un nuevo intento de Sean
Kelly por proveer una biblioteca \emph{runtime} bien organizada y mantenida, que es
una adaptación de la biblioteca \emph{runtime} de \href{http://www.dsource.org/projects/tango}{Tango} a \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0}. Sin embargo
\href{http://www.dsource.org/projects/tango}{Tango} no fue adaptada a \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0} todavía, y no hay muchas perspectivas de que
sea portada en algún momento, por un lado porque en general la comunidad sigue
fragmentada entre muchos usuarios de \href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0} que no están contentos con los
cambios introducidos en \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0}, en su mayoría usuarios de \href{http://www.dsource.org/projects/tango}{Tango}, y que no
planean migrar a esa versión; y por otro porque el desarrollo de \href{http://www.dsource.org/projects/phobos}{Phobos} 2.0
se ha abierto mucho y tiene muchos colaboradores, por lo tanto la mayor parte
de la gente que utiliza \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0} está contenta con el estado de \href{http://www.dsource.org/projects/phobos}{Phobos} 2.0.


\section{Descripción general}

\href{http://www.digitalmars.com/d/}{D} es un lenguaje de programación con sintaxis tipo C, multi-paradigma,
compilado, con \emph{tipado} fuerte y estático, buenas capacidades tanto de
programación de bajo nivel (\emph{system programming}) como de alto nivel; además
es compatible de forma binaria con C (se puede enlazar código objeto C con
código objeto D). Con estas características, \href{http://www.digitalmars.com/d/}{D} logra llenar un vacío
importante que hay entre lo lenguajes de alto bajo nivel y los de alto nivel
\hyperlink{bkip08}{{[}BKIP08{]}}. Si bien tiene herramientas de muy bajo nivel, que por lo tanto son
muy propensas a errores, da una infinidad de mecanismos para evitar el uso de
estas herramientas a menos que sea realmente necesario.  Además pone mucho
énfasis en la programación confiable, para lo cual provee muchos mecanismos
para detectar errores en los programas de forma temprana.

Si puede pensarse en C++ como un ``mejor C'', podría decirse que \href{http://www.digitalmars.com/d/}{D} es un ``mejor
C++'', ya que el objetivo del lenguaje es muy similar a C++, pero implementa
muchas características que jamás pudieron entrar en el estándar de C++ y lo
hace de una forma mucho más limpia, ya que no debe lidiar con problemas de
compatibilidad hacia atrás, y cuenta con la experiencia del camino recorrido
por C++, pudiendo extraer de él los mejores conceptos pero evitando sus
mayores problemas.

Una gran diferencia con C++ es que el análisis sintáctico (\emph{parsing}) se puede
realizar sin ningún tipo de análisis semántico, dado que a diferencia de éstos
su gramática es libre de contexto (\emph{context-free grammar}). Esto acelera
y simplifica considerablemente el proceso de compilación \hyperlink{wbb10}{{[}WBB10{]}} \hyperlink{dwov}{{[}DWOV{]}}.

Otra gran diferencia es que \href{http://www.digitalmars.com/d/}{D} decide incluir recolección de basura como parte
del lenguaje, mientras que en el comité de estandarización de C++ nunca se
llegó a un consenso para su incorporación.


\section{Características del lenguaje}

A continuación se enumeran las principales características de \href{http://www.digitalmars.com/d/}{D}, agrupadas
por unidades funcionales o paradigmas que soporta \hyperlink{dwlr}{{[}DWLR{]}}:


\hypertarget{d-generic}{}\subsection{Programación genérica y meta-programación}

La programación genérica se trata de la capacidad de poder desarrollar
algoritmos y estructuras independientes de los tipos que manipulan (pero de
forma segura o \emph{type-safe}). Esto fue muy popularizado por C++ gracias a su
soporte de plantillas (\emph{templates}) y luego otros lenguajes como \href{http://www.java.com/}{Java} y \href{http://www.ecma-international.org/publications/standards/Ecma-334.htm}{C\#}
lo siguieron. Sin embargo otros lenguajes proveen formas más avanzadas de
programación genérica, gracias a sistemas de tipos más complejos (como
\href{http://www.haskell.org/}{Haskell}).

La meta-programación se refiere en general a la capacidad de un lenguaje para
permitir generar código dentro del mismo programa de forma automática.  Esto
permite evitar duplicación de código y fue también muy popularizado por el
soporte de \emph{templates} de C++, aunque muchos otros lenguajes tienen mejor
soporte de meta-programación, en especial los lenguajes dinámicos (como
\href{http://www.python.org/}{Python}).

\href{http://www.digitalmars.com/d/}{D} provee las siguientes herramientas para realizar programación genérica
y meta-programación:
\begin{description}
\item[{\code{if} estático (\code{static if})}] \leavevmode\\
Esta construcción es similar a la directiva del preprocesador de C/C++
\code{\#if}, pero a diferencia de éste, el \code{static if} de \href{http://www.digitalmars.com/d/}{D} tiene acceso
a todos los símbolos del compilador (constantes, tipos, variables, etc)
\hyperlink{dwsi}{{[}DWSI{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{static} \PYG{k}{if} \PYG{p}{(}\PYG{p}{(}\PYG{k+kt}{void}\PYG{p}{*}\PYG{p}{)}\PYG{p}{.}\PYG{n}{sizeof} \PYG{p}{==} \PYG{l+m+mi}{4}\PYG{p}{)}
   \PYG{k}{pragma}\PYG{p}{(}\PYG{n}{msg}\PYG{p}{,} \PYG{l+s}{"32 bits"}\PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

\item[{Inferencia de tipos básica implícita y explícita (mediante \code{typeof})}] \leavevmode\\
Si no se especifica un tipo al declarar una variable, se infiere a partir
del tipo de su valor de inicialización \hyperlink{dwin}{{[}DWIN{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{static} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{5}\PYG{p}{;}      \PYG{c+c1}{// i es int}
\PYG{k}{const} \PYG{n}{d} \PYG{p}{=} \PYG{l+m+mf}{6.0}\PYG{p}{;}    \PYG{c+c1}{// d es double}
\PYG{k}{auto} \PYG{n}{s} \PYG{p}{=} \PYG{l+s}{"hola"}\PYG{p}{;} \PYG{c+c1}{// s es string (que es un alias de char[])}
\end{Verbatim}

Mediante el uso de \code{typeof} se puede solicitar el tipo de una expresión
arbitraria \hyperlink{dwto}{{[}DWTO{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{typeof}\PYG{p}{(}\PYG{l+m+mi}{5} \PYG{p}{+} \PYG{l+m+mf}{6.0}\PYG{p}{)} \PYG{n}{d}\PYG{p}{;} \PYG{c+c1}{// d es double}
\end{Verbatim}

\item[{Iteración sobre colecciones (\code{foreach})}] \leavevmode\\
Cualquier tipo de colección (arreglos estáticos y dinámicos, arreglos
asociativos, clases, estructuras o delegados) puede ser iterada mediante la
sentencia \code{foreach} \hyperlink{dwfe}{{[}DWFE{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{int}\PYG{p}{[}\PYG{p}{]} \PYG{n}{a} \PYG{p}{=} \PYG{p}{[} \PYG{l+m+mi}{1}\PYG{p}{,} \PYG{l+m+mi}{2}\PYG{p}{,} \PYG{l+m+mi}{3} \PYG{p}{]}\PYG{p}{;}
\PYG{k+kt}{int} \PYG{n}{total} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;}
\PYG{k}{foreach} \PYG{p}{(}\PYG{n}{i}\PYG{p}{;} \PYG{n}{a}\PYG{p}{)}
   \PYG{n}{total} \PYG{p}{+=} \PYG{n}{i}\PYG{p}{;}
\end{Verbatim}

\item[{\emph{Templates}}] \leavevmode\\
Tanto clases como funciones pueden ser generalizadas. Esto permite desarrollar
algoritmos genéricos sin importar el tipo de los datos de entrada, siempre
y cuando todos los tipos tengan una \emph{interfaz} común.   Esto también es
conocido como \emph{polimorfismo en tiempo de compilación}, y es la forma más
básica de programación genérica \hyperlink{dwtp}{{[}DWTP{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n}{T} \PYG{n}{sumar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{,} \PYG{n}{T} \PYG{n}{y}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{n}{x} \PYG{p}{+} \PYG{n}{y}\PYG{p}{;} \PYG{p}{\PYGZcb{}}
\PYG{k}{auto} \PYG{n}{i} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{)}\PYG{p}{(}\PYG{l+m+mi}{5}\PYG{p}{,} \PYG{l+m+mi}{6}\PYG{p}{)}\PYG{p}{;}    \PYG{c+c1}{// i == 11}
\PYG{k}{auto} \PYG{n}{f} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{float}\PYG{p}{)}\PYG{p}{(}\PYG{l+m+mi}{5}\PYG{p}{,} \PYG{l+m+mi}{6}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// j == 11.0f}
\end{Verbatim}

Además se pueden definir bloques de declaraciones generalizadas (esto no
es posible en C++), permitiendo instanciar dicho bloque con parámetros
particulares. Esto sirve como un mecanismo para la reutilización de código,
ya que puede incluirse un mismo bloque en distintos lugares (por ejemplo
clases). Un bloque generalizado puede verse como una especie de módulo.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{template} \PYG{n}{bloque}\PYG{p}{(}\PYG{n}{T}\PYG{p}{,} \PYG{n}{U}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{n}{T} \PYG{n}{x}\PYG{p}{;}
   \PYG{n}{U} \PYG{n}{foo}\PYG{p}{(}\PYG{n}{T} \PYG{n}{y}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{n}{bloque}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{,} \PYG{k+kt}{float}\PYG{p}{)}\PYG{p}{.}\PYG{n}{x} \PYG{p}{=} \PYG{l+m+mi}{5}\PYG{p}{;}
\PYG{k+kt}{float} \PYG{n}{f} \PYG{p}{=} \PYG{n}{bloque}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{,} \PYG{k+kt}{float}\PYG{p}{)}\PYG{p}{.}\PYG{n}{foo}\PYG{p}{(}\PYG{l+m+mi}{7}\PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

La utilidad más prominente de los bloques generalizados se da al
acompañarse de \emph{mixins}.

Además las \emph{templates} de \href{http://www.digitalmars.com/d/}{D} tienen las siguientes características
destacables:
\begin{description}
\item[{Instanciación implícita de funciones generalizadas}] \leavevmode\\
El lenguaje es capaz de deducir los parámetros siempre que no hayan
ambigüedades.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{auto} \PYG{n}{i} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{l+m+mi}{5}\PYG{p}{,} \PYG{l+m+mi}{6}\PYG{p}{)}\PYG{p}{;}          \PYG{c+c1}{// i == 11}
\PYG{k}{auto} \PYG{n}{f} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{l+m+mf}{5.0f}\PYG{p}{,} \PYG{l+m+mf}{6.0f}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// f == 11.0f}
\end{Verbatim}

\item[{Especialización explícita y parcial de \emph{templates}}] \leavevmode\\
La especialización de \emph{templates} consiste, al igual que en C++, en
proveer una implementación especializada para un tipo de dato (o valor)
de los parámetros.   Especialización parcial se refiere a la capacidad
de especializar un parámetro a través de un subtipo. Por ejemplo, se
puede especializar un \emph{template} para cualquier tipo de puntero, o para
cualquier tipo de arreglo dinámico, sin necesidad de especificar el tipo
al que apunta dicho puntero o el tipo almacenado por el arreglo.

Ejemplo de especialización:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n}{T} \PYG{n}{sumar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{,} \PYG{n}{T} \PYG{n}{y}\PYG{p}{)}      \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{n}{x} \PYG{p}{+} \PYG{n}{y}\PYG{p}{;} \PYG{p}{\PYGZcb{}}
\PYG{n}{T} \PYG{n}{sumar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{:} \PYG{k+kt}{int}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{,} \PYG{n}{T} \PYG{n}{y}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{n}{x} \PYG{p}{+} \PYG{n}{y} \PYG{p}{+} \PYG{l+m+mi}{1}\PYG{p}{;} \PYG{p}{\PYGZcb{}}
\PYG{k}{auto} \PYG{n}{i} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{l+m+mi}{5}\PYG{p}{,} \PYG{l+m+mi}{6}\PYG{p}{)}\PYG{p}{;}         \PYG{c+c1}{// i == 12}
\PYG{k}{auto} \PYG{n}{f} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{l+m+mf}{5.0f}\PYG{p}{,} \PYG{l+m+mf}{6.0f}\PYG{p}{)} \PYG{c+c1}{// f == 11.0f}
\end{Verbatim}

Ejemplo de especialización parcial:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n}{T} \PYG{n}{sumar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{,} \PYG{n}{T} \PYG{n}{y}\PYG{p}{)}     \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{n}{x} \PYG{p}{+} \PYG{n}{y}\PYG{p}{;} \PYG{p}{\PYGZcb{}}
\PYG{n}{T} \PYG{n}{sumar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{:} \PYG{n}{T}\PYG{p}{*}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{,} \PYG{n}{T} \PYG{n}{y}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{p}{*}\PYG{n}{x} \PYG{p}{+} \PYG{p}{*}\PYG{n}{y}\PYG{p}{;} \PYG{p}{\PYGZcb{}}
\PYG{k+kt}{int} \PYG{n}{x} \PYG{p}{=} \PYG{l+m+mi}{5}\PYG{p}{,} \PYG{n}{y} \PYG{p}{=} \PYG{l+m+mi}{6}\PYG{p}{;}
\PYG{k}{auto} \PYG{n}{i} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{p}{\&}\PYG{n}{x}\PYG{p}{,} \PYG{p}{\&}\PYG{n}{y}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// i == 11}
\PYG{k+kt}{float} \PYG{n}{v} \PYG{p}{=} \PYG{l+m+mf}{5.0f}\PYG{p}{,} \PYG{n}{w} \PYG{p}{=} \PYG{l+m+mf}{6.0f}\PYG{p}{;}
\PYG{k}{auto} \PYG{n}{f} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{p}{\&}\PYG{n}{v}\PYG{p}{,} \PYG{p}{\&}\PYG{n}{w}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// f == 11.0f}
\end{Verbatim}

\item[{Tipos, valores (incluyendo \emph{strings}) y \emph{templates} como parámetros}] \leavevmode\\
Este es otro bloque de construcción importantísimo para la programación
genérica en D, ya que combinando \emph{templates} que toman \emph{strings} como
parámetro en combinación con \emph{string mixins} pueden hacerse toda clase
de meta-programas.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{template} \PYG{n}{hash}\PYG{p}{(}\PYG{n+nb}{string} \PYG{n}{s}\PYG{p}{,} \PYG{k+kt}{uint} \PYG{n}{so\PYGZus{}far}\PYG{p}{=}\PYG{l+m+mi}{0}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{static} \PYG{k}{if} \PYG{p}{(}\PYG{n}{s}\PYG{p}{.}\PYG{n}{length} \PYG{p}{==} \PYG{l+m+mi}{0}\PYG{p}{)}
      \PYG{k}{const} \PYG{n}{hash} \PYG{p}{=} \PYG{n}{so\PYGZus{}far}\PYG{p}{;}
   \PYG{k}{else}
      \PYG{k}{const} \PYG{n}{hash} \PYG{p}{=} \PYG{n}{hash}\PYG{p}{!}\PYG{p}{(}\PYG{n}{s}\PYG{p}{[}\PYG{l+m+mi}{1} \PYG{p}{..} \PYG{n}{length}\PYG{p}{]}\PYG{p}{,} \PYG{n}{so\PYGZus{}far} \PYG{p}{*} \PYG{l+m+mi}{11} \PYG{p}{+} \PYG{n}{s}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{n+nb}{string} \PYG{n}{s} \PYG{p}{=} \PYG{n}{hash}\PYG{p}{!}\PYG{p}{(}\PYG{l+s}{"hola"}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// calculado en tiempo de compilación}
\end{Verbatim}

\item[{Cantidad de parámetros variables para \emph{templates}}] \leavevmode\\
Esta característica permite implementar tuplas y otros algoritmos que
inherentemente deben tomar una cantidad variable de parámetros en tiempo
de compilación.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{double} \PYG{n}{sumar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{...}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{t}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{double} \PYG{n}{res} \PYG{p}{=} \PYG{l+m+mf}{0.0}\PYG{p}{;}
   \PYG{k}{foreach} \PYG{p}{(}\PYG{n}{x}\PYG{p}{;} \PYG{n}{t}\PYG{p}{)}
      \PYG{n}{res} \PYG{p}{+=} \PYG{n}{x}\PYG{p}{;}
   \PYG{k}{return} \PYG{n}{res}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k+kt}{double} \PYG{n}{d} \PYG{p}{=} \PYG{n}{sumar}\PYG{p}{(}\PYG{l+m+mi}{1}\PYG{p}{,} \PYG{l+m+mf}{2.0}\PYG{p}{,} \PYG{l+m+mf}{3.0f}\PYG{p}{,} \PYG{l+m+mi}{4}\PYG{n}{l}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// d == 10.0}
\end{Verbatim}

\end{description}

\item[{\emph{CTFE} (\emph{compile-time function execution})}] \leavevmode\\
Si una función cumple ciertas reglas básicas (como por ejemplo no tener
efectos colaterales) puede ser ejecutada en tiempo de compilación en vez de
tiempo de ejecución. Esto permite hacer algunos cálculos que no cambian de
ejecución en ejecución al momento de compilar, mejorando el rendimiento
o permitiendo formas avanzadas de meta-programación. Esta característica se
vuelve particularmente útil al combinarse con \emph{string mixins} \hyperlink{dwcf}{{[}DWCF{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{int} \PYG{n}{factorial}\PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{n}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{n} \PYG{p}{==} \PYG{l+m+mi}{1}\PYG{p}{)}
      \PYG{k}{return} \PYG{l+m+mi}{1}\PYG{p}{;}
   \PYG{k}{else}
      \PYG{k}{return} \PYG{n}{n} \PYG{p}{*} \PYG{n}{factorial}\PYG{p}{(}\PYG{n}{n} \PYG{p}{-} \PYG{l+m+mi}{1}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k}{static} \PYG{k+kt}{int} \PYG{n}{x} \PYG{p}{=} \PYG{n}{factorial}\PYG{p}{(}\PYG{l+m+mi}{5}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// calculado en tiempo de compilación}
\PYG{k+kt}{int} \PYG{n}{x} \PYG{p}{=} \PYG{n}{factorial}\PYG{p}{(}\PYG{l+m+mi}{5}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// calculado en tiempo de ejecución}
\end{Verbatim}

Esta característica es muy importante para evitar la duplicación de código.

\item[{\emph{Mixins}, incluyendo \emph{string mixins}}] \leavevmode\\
La palabra \emph{mixin} tiene significados distintos en varios lenguajes de
programación. En \href{http://www.digitalmars.com/d/}{D} \emph{mixin} significa tomar una secuencia arbitraria de
declaraciones e insertarla en el contexto (\emph{scope}) actual. Esto puede
realizarse a nivel global, en clases, estructuras o funciones. Esto sirve
como un mecanismo para evitar duplicación de código que puede ser
introducida por la falta de herencia múltiple \hyperlink{dwmt}{{[}DWMT{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{A} \PYG{p}{\PYGZob{}}
   \PYG{k}{mixin} \PYG{n}{bloque}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{,} \PYG{k+kt}{float}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{n}{A} \PYG{n}{a} \PYG{p}{=} \PYG{k}{new} \PYG{n}{A}\PYG{p}{;}
\PYG{n}{a}\PYG{p}{.}\PYG{n}{x} \PYG{p}{=} \PYG{l+m+mi}{5}\PYG{p}{;}
\PYG{k+kt}{float} \PYG{n}{f} \PYG{p}{=} \PYG{n}{a}\PYG{p}{.}\PYG{n}{foo}\PYG{p}{(}\PYG{n}{a}\PYG{p}{.}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}

\PYG{k}{class} \PYG{n}{B} \PYG{p}{\PYGZob{}}
   \PYG{k}{mixin} \PYG{n}{bloque}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{long}\PYG{p}{,} \PYG{k+kt}{double}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{n}{B} \PYG{n}{b} \PYG{p}{=} \PYG{k}{new} \PYG{n}{B}\PYG{p}{;}
\PYG{n}{b}\PYG{p}{.}\PYG{n}{x} \PYG{p}{=} \PYG{l+m+mi}{5}\PYG{n}{l}\PYG{p}{;}
\PYG{k+kt}{double} \PYG{n}{d} \PYG{p}{=} \PYG{n}{a}\PYG{p}{.}\PYG{n}{foo}\PYG{p}{(}\PYG{n}{a}\PYG{p}{.}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

\emph{String mixin} se refiere a la capacidad de \emph{incrustar} un \emph{string} que
contenga un fragmento de código en un programa como si este fragmento
hubiera sido escrito en el código fuente directamente por el programador.
Esto permite hacer manipulaciones arbitrariamente complejas en combinación
con funciones ejecutadas en tiempo de compilación \hyperlink{dwme}{{[}DWME{]}} \hyperlink{dwmx}{{[}DWMX{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n+nb}{string} \PYG{n}{generar\PYGZus{}sumar}\PYG{p}{(}\PYG{n+nb}{string} \PYG{n}{var\PYGZus{}x}\PYG{p}{,} \PYG{n+nb}{string} \PYG{n}{var\PYGZus{}y}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{return} \PYG{l+s}{"return "} \PYG{p}{\textasciitilde{}} \PYG{n}{var\PYGZus{}x} \PYG{p}{\textasciitilde{}} \PYG{l+s}{" + "} \PYG{p}{\textasciitilde{}} \PYG{n}{var\PYGZus{}y} \PYG{p}{\textasciitilde{}} \PYG{l+s}{";"}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k+kt}{int} \PYG{n}{sumar}\PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{a}\PYG{p}{,} \PYG{k+kt}{int} \PYG{n}{b}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{mixin}\PYG{p}{(}\PYG{n}{generar\PYGZus{}sumar}\PYG{p}{!}\PYG{p}{(}\PYG{l+s}{"a"}\PYG{p}{,} \PYG{l+s}{"b"}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\item[{Expresiones \code{is}}] \leavevmode\\
Las \emph{expresiones {}`{}`is{}`{}`} permiten la compilación condicional basada en las
características de un tipo \hyperlink{dwie}{{[}DWIE{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n}{T} \PYG{n}{foo}\PYG{p}{(}\PYG{n}{T}\PYG{p}{)}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{static} \PYG{k}{if} \PYG{p}{(}\PYG{k}{is}\PYG{p}{(}\PYG{n}{T} \PYG{p}{==} \PYG{k}{class}\PYG{p}{)}\PYG{p}{)}
      \PYG{k}{return} \PYG{k}{new} \PYG{n}{T}\PYG{p}{;}
   \PYG{k}{else}
      \PYG{k}{return} \PYG{n}{T}\PYG{p}{.}\PYG{n}{init}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

Esto provee además una forma simple de reflexión en tiempo de compilación.

\end{description}
\hypertarget{d-low-level}{}

\subsection{Programación de bajo nivel (\emph{system programming})}

Por programación de bajo nivel nos referimos a la capacidad de un lenguaje de
manipular el hardware directamente, o al menos la memoria. C es probablemente
el lenguaje de bajo nivel más popular, seguido por C++.

\href{http://www.digitalmars.com/d/}{D} presenta muchas características de bajo nivel:
\begin{description}
\item[{Compila a código de máquina nativo}] \leavevmode\\
Los programas generados por \href{http://www.digitalmars.com/d/}{D} no son interpretados ni necesitan una
máquina virtual como otros lenguajes de más alto nivel como \href{http://www.java.com/}{Java}, \href{http://www.ecma-international.org/publications/standards/Ecma-334.htm}{C\#},
\href{http://www.python.org/}{Python}, etc \hyperlink{dwov}{{[}DWOV{]}}.

\item[{\emph{Assembly} empotrado}] \leavevmode\\
Provee acceso directo al \emph{hardware} y la posibilidad de utilizar cualquier
característica de éste que no esté disponible en el lenguaje.

Una ventaja sobre C y C++ es que el lenguaje \emph{assembly} utilizado dentro de
\href{http://www.digitalmars.com/d/}{D} está especificado, por lo que se puede mantener la portabilidad entre
compiladores incluso cuando se utiliza \emph{assembly} (mientras que no se
cambie de arquitectura, por supuesto) \hyperlink{dwia}{{[}DWIA{]}}.

\item[{\code{goto}}] \leavevmode\\
Al igual que C y C++, \href{http://www.digitalmars.com/d/}{D} provee la flexibilidad del uso de \code{goto}
\hyperlink{dwgt}{{[}DWGT{]}}.

\item[{Compatibilidad con C}] \leavevmode\\
Soporta todos los tipos de C y es ABI \footnote{
Interfaz de Aplicación Binaria (del inglés \emph{Application Binary
Interface}).
} compatible con éste. Esto
permite enlazar archivos objeto estándar de C y \href{http://www.digitalmars.com/d/}{D} en un mismo programa.
Además permite interoperar con C a través de \code{extern (C)} \hyperlink{dwcc}{{[}DWCC{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{extern} \PYG{p}{(}\PYG{n}{C}\PYG{p}{)} \PYG{n}{printf}\PYG{p}{(}\PYG{k}{const} \PYG{k+kt}{char}\PYG{p}{*} \PYG{n}{format}\PYG{p}{,} \PYG{p}{...}\PYG{p}{)}\PYG{p}{;}
\PYG{n}{printf}\PYG{p}{(}\PYG{l+s}{"3 + 5 == \%d\PYGZbs{}n"}\PYG{p}{,} \PYG{l+m+mi}{3} \PYG{p}{+} \PYG{l+m+mi}{5}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// llama al printf de C}
\end{Verbatim}

\item[{Manejo de memoria explícito}] \leavevmode\\
Permite asignar estructuras en el \emph{stack} o en el \emph{heap}, haciendo uso de
los servicios del sistema operativo o la biblioteca estándar de C \hyperlink{dwmm}{{[}DWMM{]}}.

\item[{Objetos y arreglos \emph{livianos}}] \leavevmode\\
Por objetos \emph{livianos} se entiende no-polimórficos. Es decir, un
agrupamiento de variables análogo al \code{struct} de C, sin tabla virtual ni
otro tipo de \emph{overhead}. Los arreglos \emph{livianos} son arreglos estáticos
como en C, cuyo tamaño es fijo, también sin ningún tipo de \emph{overhead} como
C. Además puede asignarse un arreglo dinámicamente usando \code{malloc()}
y utilizar el operador \code{{[}{]}} para accederlo \hyperlink{dwst}{{[}DWST{]}} \hyperlink{dwcl}{{[}DWCL{]}}.

Esto también permite interoperar con C, ya que pueden definirse \code{structs}
y arreglos que pueden ser intercambiados con dicho lenguaje sin problemas.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{struct} \PYG{n}{timeval} \PYG{p}{\PYGZob{}}
   \PYG{n}{time\PYGZus{}t}         \PYG{n}{tv\PYGZus{}sec}\PYG{p}{;}
   \PYG{n}{suseconds\PYGZus{}t} \PYG{n}{tv\PYGZus{}usec}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k}{extern} \PYG{p}{(}\PYG{n}{C}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{malloc}\PYG{p}{(}\PYG{n}{size\PYGZus{}t}\PYG{p}{)}\PYG{p}{;}
   \PYG{n}{size\PYGZus{}t} \PYG{n}{strlen}\PYG{p}{(}\PYG{k}{const} \PYG{k+kt}{char} \PYG{p}{*}\PYG{p}{)}\PYG{p}{;}
   \PYG{k+kt}{int} \PYG{n}{gettimeofday}\PYG{p}{(}\PYG{n}{timeval} \PYG{p}{*}\PYG{p}{,} \PYG{k+kt}{void} \PYG{p}{*}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k+kt}{char}\PYG{p}{*} \PYG{n}{s} \PYG{p}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{k+kt}{char}\PYG{p}{*}\PYG{p}{)} \PYG{n}{malloc}\PYG{p}{(}\PYG{l+m+mi}{2}\PYG{p}{)}\PYG{p}{;}
\PYG{n}{s}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]} \PYG{p}{=} \PYG{l+s+sc}{'C'}\PYG{p}{;}
\PYG{n}{s}\PYG{p}{[}\PYG{l+m+mi}{1}\PYG{p}{]} \PYG{p}{=} \PYG{l+s+sc}{'\PYGZbs{}0'}\PYG{p}{;}
\PYG{n}{size\PYGZus{}t} \PYG{n}{l} \PYG{p}{=} \PYG{n}{strlen}\PYG{p}{(}\PYG{n}{s}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// l == 1}
\PYG{n}{timeval} \PYG{n}{tv}\PYG{p}{;}
\PYG{n}{gettimeofday}\PYG{p}{(}\PYG{p}{\&}\PYG{n}{tv}\PYG{p}{,} \PYG{k+kc}{null}\PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

\item[{Rendimiento}] \leavevmode\\
La \hyperlink{d-generic}{\emph{Programación genérica y meta-programación}} permite realizar muchas optimizaciones ya que se
resuelve en tiempo de compilación y por lo tanto aumenta el rendimiento en
la ejecución \hyperlink{dwtp}{{[}DWTP{]}}.

\item[{Número de punto flotante de 80 bits}] \leavevmode\\
El tipo \code{real} de \href{http://www.digitalmars.com/d/}{D} tiene precisión de 80 bits si la plataforma lo
soporta (por ejemplo en i386) \hyperlink{dwty}{{[}DWTY{]}}.

\item[{Control de alineación de miembros de una estructura}] \leavevmode\\
Mediante \code{align} se puede especificar la alineación a tener en una
estructura \hyperlink{dwal}{{[}DWAL{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{align} \PYG{p}{(}\PYG{l+m+mi}{1}\PYG{p}{)}
\PYG{k}{struct} \PYG{n}{paquete\PYGZus{}de\PYGZus{}red} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{char}   \PYG{n}{tipo}\PYG{p}{;}
   \PYG{k+kt}{short} \PYG{n}{valor}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{c+c1}{// paquete\PYGZus{}de\PYGZus{}red.sizeof == 3}
\end{Verbatim}

\end{description}
\hypertarget{d-high-level}{}

\subsection{Programación de alto nivel}

Programación de alto nivel se refiere a construcciones más avanzadas que una
sentencia para iterar; expresiones con una semántica más ricas que proveen de
mayor expresividad al programador o le permiten focalizarse de mejor manera
en los algoritmos independizándose del \emph{hardware} o de como funciona una
computadora. Es exactamente el opuesto a \hyperlink{d-low-level}{\emph{Programación de bajo nivel (system programming)}}.

En general estas características tienen como efecto secundario una mejora de la
productividad de los programadores. \href{http://www.digitalmars.com/d/}{D} adopta herramientas de muchos lenguajes
de alto nivel, como \href{http://www.java.com/}{Java} y \href{http://www.python.org/}{Python}, por ejemplo:
\begin{description}
\item[{Manejo automático de memoria}] \leavevmode\\
Al igual que C/C++ y prácticamente cualquier lenguaje imperativo maneja
automáticamente el \emph{stack}, pero a diferencia de la mayoría de los
lenguajes de bajo nivel, \href{http://www.digitalmars.com/d/}{D} permite manejar el \emph{heap} de manera automática
también a través de un \emph{recolector de basura} \hyperlink{dwgc}{{[}DWGC{]}}.

\item[{Sistema de paquetes y módulos (similar a \href{http://www.java.com/}{Java} o \href{http://www.python.org/}{Python})}] \leavevmode\\
Un módulo es una unidad que agrupa clases, funciones y cualquier otra
construcción de lenguaje. Un paquete es una agrupación de módulos. \href{http://www.digitalmars.com/d/}{D}
asocia un módulo a un archivo fuente (y un archivo objeto cuando éste es
compilado) y un paquete a un directorio. A diferencia de C/C++ no necesita
de un preprocesador para incluir declaraciones de otros \emph{módulos} (en C/C++
no existe el concepto de módulo, solo de unidades de compilación) \hyperlink{dwmo}{{[}DWMO{]}}.

Ejemplo:

\code{a.d}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{module} \PYG{n}{a}\PYG{p}{;}
\PYG{k+kt}{void} \PYG{n}{f}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\code{b.d}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{module} \PYG{n}{b}\PYG{p}{;}
\PYG{k+kt}{void} \PYG{n}{f}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\code{c.d}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{module} \PYG{n}{c}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{a}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{b}\PYG{p}{:} \PYG{n}{f}\PYG{p}{;}
\PYG{n}{a}\PYG{p}{.}\PYG{n}{f}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
\PYG{n}{b}\PYG{p}{.}\PYG{n}{f}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
\PYG{n}{f}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// ejecuta b.f()}
\end{Verbatim}

\item[{Funciones y delegados}] \leavevmode\\
Las funciones pueden ser sobrecargadas (funciones con el mismo nombre pero
distinta cantidad o tipo de parámetros), pueden especificarse argumentos de
entrada, salida o entrada/salida, argumentos por omisión o argumentos
evaluados de forma perezosa (\emph{lazy}). Además pueden tener una cantidad de
argumentos variables pero manteniendo información de tipos (más seguro que
C/C++) \hyperlink{dwfu}{{[}DWFU{]}}.

Los \emph{delegados} son punteros a función con un contexto asociado. Este
contexto puede ser un objeto (en cuyo caso la función es un método) o un
\emph{stack frame} (en cuyo caso la función es una función anidada).

Además de esto los delegados son ciudadanos de primera clase
\footnote{
Por ciudadano de primera clase se entiende que se trata
de un tipo soportado por completo por el lenguaje, disponiendo de
expresiones literales anónimas, pudiendo ser almacenados en variables,
estructuras de datos, teniendo una identidad intrínseca, más allá de un
nombre dado, etc. En realidad los arreglos asociativos no pueden ser
expresados como literales anónimos pero sí tienen una sintaxis especial
soportada directamente por el lenguaje.
}, disponiendo de forma literal (delegado anónimo), lo que
permite construcciones de alto nivel muy conveniente. Los argumentos
evaluados de forma perezosa no son más que un delegado que se ejecuta solo
cuando es necesario.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{bool} \PYG{n}{buscar}\PYG{p}{(}\PYG{n}{T}\PYG{p}{[}\PYG{p}{]} \PYG{n}{arreglo}\PYG{p}{,} \PYG{n}{T} \PYG{n}{item}\PYG{p}{,} \PYG{k+kt}{bool} \PYG{k}{delegate}\PYG{p}{(}\PYG{n}{T} \PYG{n}{x}\PYG{p}{,} \PYG{n}{T} \PYG{n}{y}\PYG{p}{)} \PYG{n}{igual}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{foreach} \PYG{p}{(}\PYG{n}{t}\PYG{p}{,} \PYG{n}{arreglo}\PYG{p}{)}
      \PYG{k}{if} \PYG{p}{(}\PYG{n}{igual}\PYG{p}{(}\PYG{n}{t}\PYG{p}{,} \PYG{n}{item}\PYG{p}{)}\PYG{p}{)}
         \PYG{k}{return} \PYG{k+kc}{true}\PYG{p}{;}
   \PYG{k}{return} \PYG{k+kc}{false}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k}{struct} \PYG{n}{Persona} \PYG{p}{\PYGZob{}}
   \PYG{n+nb}{string} \PYG{n}{nombre}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{n}{Persona}\PYG{p}{[}\PYG{p}{]} \PYG{n}{personas}\PYG{p}{;}
\PYG{c+c1}{// llenas personas}
\PYG{n}{Persona} \PYG{n}{p}\PYG{p}{;}
\PYG{n}{p}\PYG{p}{.}\PYG{n}{nombre} \PYG{p}{=} \PYG{l+s}{"Carlos"}\PYG{p}{;}
\PYG{k+kt}{bool} \PYG{n}{encontrado} \PYG{p}{=} \PYG{n}{buscar}\PYG{p}{(}\PYG{n}{personas}\PYG{p}{,} \PYG{n}{p}\PYG{p}{,}
                                 \PYG{p}{(}\PYG{n}{Persona} \PYG{n}{x}\PYG{p}{,} \PYG{n}{Persona} \PYG{n}{y}\PYG{p}{)} \PYG{p}{\PYGZob{}}
                                    \PYG{k}{return} \PYG{n}{x}\PYG{p}{.}\PYG{n}{nombre} \PYG{p}{==} \PYG{n}{y}\PYG{p}{.}\PYG{n}{nombre}\PYG{p}{;}
                                 \PYG{p}{\PYGZcb{}}
                           \PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

\item[{Arreglos \emph{dinámicos} y arreglos asociativos}] \leavevmode\\
Los arreglos \emph{dinámicos} son arreglos de longitud variable manejados
automáticamente por el lenguaje (análogos al \code{std::vector} de C++).
Soportan concatenación (a través del operador \code{\textasciitilde{}}), rebanado o \emph{slicing}
(a través del operador \code{{[}x..y{]}}) y chequeo de límites (\emph{bound checking})
\hyperlink{dwar}{{[}DWAR{]}}.

Los arreglos asociativos (también conocidos como \emph{hashes} o diccionarios)
también son provistos por el lenguaje \hyperlink{dwaa}{{[}DWAA{]}}.

Ambos son ciudadanos de primera clase, disponiendo de forma literal.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{int}\PYG{p}{[}\PYG{p}{]} \PYG{n}{primos} \PYG{p}{=} \PYG{p}{[} \PYG{l+m+mi}{2}\PYG{p}{,} \PYG{l+m+mi}{3}\PYG{p}{,} \PYG{l+m+mi}{5}\PYG{p}{,} \PYG{l+m+mi}{7}\PYG{p}{,} \PYG{l+m+mi}{11}\PYG{p}{,} \PYG{l+m+mi}{13}\PYG{p}{,} \PYG{l+m+mi}{17}\PYG{p}{,} \PYG{l+m+mi}{19} \PYG{p}{]}\PYG{p}{;}
\PYG{n}{primos} \PYG{p}{\textasciitilde{}=} \PYG{p}{[} \PYG{l+m+mi}{23}\PYG{p}{,} \PYG{l+m+mi}{29} \PYG{p}{]}\PYG{p}{;}
\PYG{k}{auto} \PYG{n}{menores\PYGZus{}que\PYGZus{}10} \PYG{p}{=} \PYG{n}{primos}\PYG{p}{[}\PYG{l+m+mf}{0.}\PYG{l+m+mf}{.4}\PYG{p}{]}\PYG{p}{;} \PYG{c+c1}{// [ 2, 3, 5, 7 ]}
\PYG{k+kt}{int}\PYG{p}{[}\PYG{n+nb}{string}\PYG{p}{]} \PYG{n}{agenda}\PYG{p}{;}
\PYG{n}{agenda}\PYG{p}{[}\PYG{l+s}{"Pepe"}\PYG{p}{]} \PYG{p}{=} \PYG{l+m+mi}{5555\PYGZus{}1234}\PYG{p}{;}
\end{Verbatim}

\item[{\emph{Strings}}] \leavevmode\\
Al igual que los delegados y arreglos dinámicos y asociativos, los
\emph{strings} son ciudadanos de primera clase, teniendo forma literal y siendo
codificados en UTF-8/16/32. Son un caso particular de arreglo dinámico y es
posible utilizarlos en sentencias \code{switch}/\code{case} \hyperlink{dwsr}{{[}DWSR{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n+nb}{string} \PYG{n}{s} \PYG{p}{=} \PYG{l+s}{"árbol"}\PYG{p}{;}

\PYG{k}{switch} \PYG{p}{(}\PYG{n}{s}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{case} \PYG{l+s}{"árbol"}\PYG{p}{:}
      \PYG{n}{s} \PYG{p}{=} \PYG{l+s}{"tree"}\PYG{p}{;}
   \PYG{k}{default}\PYG{p}{:}
      \PYG{n}{s} \PYG{p}{=} \PYG{l+s}{""}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\item[{\code{typedef} y \code{alias}}] \leavevmode\\
El primero define un nuevo tipo basado en otro. A diferencia de C/C++ el
tipo original no puede ser implícitamente convertido al tipo nuevo (excepto
valores literales), pero la conversión es válida en el otro sentido
(similar a los \code{enum} en C++). Por el contrario, \code{alias} es análogo al
\code{typedef} de C/C++ y simplemente es una forma de referirse al mismo tipo
con un nombre distinto \hyperlink{dwdc}{{[}DWDC{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{typedef} \PYG{k+kt}{int} \PYG{n}{tipo}\PYG{p}{;}
\PYG{k+kt}{int} \PYG{n}{foo}\PYG{p}{(}\PYG{n}{tipo} \PYG{n}{x}\PYG{p}{)} \PYG{p}{\PYGZob{}}\PYG{p}{\PYGZcb{}}
\PYG{n}{tipo} \PYG{n}{t} \PYG{p}{=} \PYG{l+m+mi}{10}\PYG{p}{;}
\PYG{k+kt}{int} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{10}\PYG{p}{;}
\PYG{n}{foo}\PYG{p}{(}\PYG{n}{t}\PYG{p}{)}\PYG{p}{;}
\PYG{n}{foo}\PYG{p}{(}\PYG{n}{i}\PYG{p}{)}\PYG{p}{;} \PYG{c+c1}{// error, no compila}
\PYG{k}{alias} \PYG{n}{tipo} \PYG{n}{un\PYGZus{}alias}\PYG{p}{;}
\PYG{n}{un\PYGZus{}alias} \PYG{n}{a} \PYG{p}{=} \PYG{n}{t}\PYG{p}{;}
\PYG{n}{foo}\PYG{p}{(}\PYG{n}{a}\PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

\item[{Documentación embebida}] \leavevmode\\
\href{http://www.digitalmars.com/d/}{D} provee un sistema de documentación embebida, análogo a lo que proveen
\href{http://www.java.com/}{Java} o \href{http://www.python.org/}{Python} en menor medida. Hay comentarios especiales del código que
pueden ser utilizados para documentarlo de forma tal que luego el
compilador pueda extraer esa información para generar un documento \hyperlink{dwdo}{{[}DWDO{]}}.

\item[{Números complejos}] \leavevmode\\
\href{http://www.digitalmars.com/d/}{D} soporta números complejos como ciudadanos de primera clase. Soporta
forma literal de números imaginarios y complejos \hyperlink{dwty}{{[}DWTY{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{ifloat} \PYG{n}{im} \PYG{p}{=} \PYG{l+m+mf}{5.0i}\PYG{p}{;}
\PYG{k+kt}{float}   \PYG{n}{re} \PYG{p}{=} \PYG{l+m+mf}{1.0}\PYG{p}{;}
\PYG{k+kt}{cfloat} \PYG{n}{c}   \PYG{p}{=} \PYG{n}{re} \PYG{p}{+} \PYG{n}{im}\PYG{p}{;} \PYG{c+c1}{// c == 1.0 + 5.0i}
\end{Verbatim}

\end{description}


\subsection{Programación orientada a objetos}

La orientación a objetos es probablemente el paradigma más utilizado en la
actualidad a la hora de diseñar e implementar un programa. \href{http://www.digitalmars.com/d/}{D} provee muchas
herramientas para soportar este paradigma de forma confiable. Entre las
características más salientes se encuentran:
\begin{description}
\item[{Objetos \emph{pesados}}] \leavevmode\\
Objetos polimórficos como los de cualquier lenguaje con orientación real
a objetos. Estos objetos poseen una tabla virtual para despacho dinámico,
todos los métodos son virtuales a menos que se indique lo contrario
y tienen semántica de referencia \footnote{
Semántica de referencia significa que el tipo es tratado como
si fuera un puntero. Nunca se hacen copias del objeto, siempre se pasa
por referencia.
}. Estos objetos tienen un
\emph{overhead} comparados a los objetos \emph{livianos} pero aseguran una semántica
segura para trabajar con orientación a objetos, evitando problemas con los
que se enfrenta C++ (como \emph{slicing} \footnote{
Este problema se da en C++ cuando se pasa una clase derivada
a una función que acepta una clase base por valor como parámetro. Al
realizarse una copia de la clase con el constructor de copia de la clase
base, se pierden (o \emph{rebanan}) los atributos de la clase derivada, y la
información de tipos en tiempo de ejecución (\emph{RTTI}).
}) debido a que permite
semántica por valor \footnote{
Semántica de valor significa que el tipo es tratado como si
fuera un valor concreto. En general se pasa por valor y se hacen copias
a menos que se utilice explícitamente un puntero.
} \hyperlink{dwcl}{{[}DWCL{]}}.

\href{http://www.digitalmars.com/d/}{D} además soporta tipos de retorno covariantes para funciones virtuales.
Esto significa que una función sobreescrita por una clase derivada puede
retornar un tipo que sea derivado del tipo retornado por la función
original sobreescrita \hyperlink{dwfu}{{[}DWFU{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{A} \PYG{p}{\PYGZob{}} \PYG{p}{\PYGZcb{}}
\PYG{k}{class} \PYG{n}{B} \PYG{p}{:} \PYG{n}{A} \PYG{p}{\PYGZob{}} \PYG{p}{\PYGZcb{}}

\PYG{k}{class} \PYG{n}{Foo} \PYG{p}{\PYGZob{}}
   \PYG{n}{A} \PYG{n}{test}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{k+kc}{null}\PYG{p}{;} \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}

\PYG{k}{class} \PYG{n}{Bar} \PYG{p}{:} \PYG{n}{Foo} \PYG{p}{\PYGZob{}}
   \PYG{n}{B} \PYG{n}{test}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{k+kc}{null}\PYG{p}{;} \PYG{p}{\PYGZcb{}} \PYG{c+c1}{// sobreescribe y es covariante con Foo.test()}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\item[{Interfaces}] \leavevmode\\
\href{http://www.digitalmars.com/d/}{D} no soporta herencia múltiple pero sí interfaces. Una interfaz es
básicamente una tabla virtual, una definición de métodos virtuales que debe
proveer una clase. Las interfaces no proveen una implementación de dichos
métodos, ni pueden tener atributos. Esto simplifica mucho el lenguaje y no
se pierde flexibilidad porque puede conseguirse el mismo efecto de tener
herencia múltiple a través de interfaces y \emph{mixins} para proveer una
implementación o atributos en común a varias clases que implementan la
misma interfaz \hyperlink{dwif}{{[}DWIF{]}}.

\item[{Sobrecarga de operadores}] \leavevmode\\
La sobrecarga de operadores permite que un objeto tenga una sintaxis
similar a un tipo de dato nativo. Esto es muy importante además para la
programación genérica \hyperlink{dwoo}{{[}DWOO{]}}.

\item[{Clases anidadas}] \leavevmode\\
Al igual que C (con respecto a \code{struct}) y C++, pueden anidarse clases
dentro de clases. \href{http://www.digitalmars.com/d/}{D} sin embargo provee la posibilidad de acceder
a atributos de la instancia exterior desde la anidada \hyperlink{dwnc}{{[}DWNC{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Exterior} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{int} \PYG{n}{m}\PYG{p}{;}
   \PYG{k}{class} \PYG{n}{Anidada} \PYG{p}{\PYGZob{}}
      \PYG{k+kt}{int} \PYG{n}{foo}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}
         \PYG{k}{return} \PYG{n}{m}\PYG{p}{;} \PYG{c+c1}{// ok, puede acceder a un miembro de Exterior}
      \PYG{p}{\PYGZcb{}}
   \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

Esto tiene un pequeño \emph{overhead} ya que la clase \code{Anidada} debe guardar
un puntero a la clase \code{Exterior}. Si no se necesita este comportamiento
es posible evitar este \emph{overhead} utilizando \code{static}, en cuyo caso solo
puede acceder a atributos estáticos de la clase \code{Exterior}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Exterior} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{int} \PYG{n}{m}\PYG{p}{;}
   \PYG{k}{static} \PYG{k+kt}{int} \PYG{n}{n}\PYG{p}{;}
   \PYG{k}{static} \PYG{k}{class} \PYG{n}{Anidada} \PYG{p}{\PYGZob{}}
      \PYG{k+kt}{int} \PYG{n}{foo}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}
         \PYG{c+c1}{//return m; // error, miembro de Exterior}
         \PYG{k}{return} \PYG{n}{n}\PYG{p}{;} \PYG{c+c1}{// ok,   miembro estático de Exterior}
      \PYG{p}{\PYGZcb{}}
   \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\item[{Propiedades (\emph{properties})}] \leavevmode\\
En \href{http://www.digitalmars.com/d/}{D} se refiere a funciones miembro que pueden ser tratadas
sintácticamente como campos de esa clase/estructura \hyperlink{dwpr}{{[}DWPR{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Foo} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{int} \PYG{n}{data}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{n}{\PYGZus{}data}\PYG{p}{;} \PYG{p}{\PYGZcb{}} \PYG{c+c1}{// propiedad de lectura}
   \PYG{k+kt}{int} \PYG{n}{data}\PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{value}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{k}{return} \PYG{n}{\PYGZus{}data} \PYG{p}{=} \PYG{n}{value}\PYG{p}{;} \PYG{p}{\PYGZcb{}} \PYG{c+c1}{// de escritura}
   \PYG{k}{private} \PYG{k+kt}{int} \PYG{n}{\PYGZus{}data}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{n}{Foo} \PYG{n}{f} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Foo}\PYG{p}{;}
\PYG{n}{f}\PYG{p}{.}\PYG{n}{data} \PYG{p}{=} \PYG{l+m+mi}{1}\PYG{p}{;}       \PYG{c+c1}{// llama a f.data(1)}
\PYG{k+kt}{int} \PYG{n}{i} \PYG{p}{=} \PYG{n}{f}\PYG{p}{.}\PYG{n}{data}\PYG{p}{;} \PYG{c+c1}{// llama a f.data()}
\end{Verbatim}

Además tipos nativos, clases, estructuras y expresiones tienen
\emph{properties} predefinidos, por ejemplo:
\begin{description}
\item[{\code{sizeof}}] \leavevmode\\
Tamaño ocupado en memoria (ejemplo: \code{int.sizeof} -\textgreater{} 4).

\item[{\code{init}}] \leavevmode\\
Valor de inicialización por omisión (ejemplo: \code{float.init} -\textgreater{} \emph{NaN}
\footnote{
Del inglés \emph{Not A Number}, es un valor especial codificado según
IEEE 754-2008 \hyperlink{ieee754}{{[}IEEE754{]}} que indica que estamos ante un valor inválido.
}).

\end{description}
\begin{description}
\item[{\code{stringof}}] \leavevmode\\
Representación textual del símbolo o expresión (ejemplo:
\code{(1+2).stringof} -\textgreater{} \code{"1 + 2"}).

\item[{\code{mangleof}}] \leavevmode\\
Representación textual del tipo \emph{mutilado} \footnote{
\emph{Name mangling} es el nombre dado comúnmente a una técnica
necesaria para poder sobrecargar nombres de símbolos. Consiste en
codificar los nombres de las funciones tomando como entrada el nombre de
la función y la cantidad y tipo de parámetros, asegurando que dos
funciones con el mismo nombre pero distintos parámetros (sobrecargada)
tengan nombres distintos.
} \hyperlink{dwab}{{[}DWAB{]}}.

\end{description}
\begin{description}
\item[{\code{alignof}}] \leavevmode\\
Alineación de una estructura o tipo.

\end{description}

Estos son solo los \emph{properties} predefinidos para todos los tipos, pero hay
una cantidad considerable de \emph{properties} extra para cada tipo.

\end{description}
\hypertarget{d-dbc}{}

\subsection{Programación confiable}

Programación confiable se refiere a las capacidades o facilidades que provee
el lenguaje para evitar fallas de manera temprana (o la capacidad de evitar
que ciertas fallas puedan existir directamente). \href{http://www.digitalmars.com/d/}{D} presta particular atención
a esto y provee las siguientes herramientas:
\begin{description}
\item[{Excepciones}] \leavevmode\\
\href{http://www.digitalmars.com/d/}{D} soporta excepciones de manera similar a \href{http://www.java.com/}{Java}: provee \code{try}, \code{catch}
y \code{finally}. Esto permite que los errores difícilmente pasen
silenciosamente sin ser detectados \hyperlink{dwex}{{[}DWEX{]}}.

\item[{\code{assert}}] \leavevmode\\
Es una condición que debe cumplirse siempre en un programa, como un chequeo
de integridad. Esto es muy utilizado en C/C++, donde \code{assert()} es una
\emph{macro} que solo se compila cuando la \emph{macro} \code{NDEBUG} no está definida.
Esto permite eliminar los chequeos de integridad del programa, que pueden
ser costosos, para versiones que se suponen estables.

\href{http://www.digitalmars.com/d/}{D} lleva este concepto más allá y hace al \code{assert} parte del lenguaje
\hyperlink{dwcp}{{[}DWCP{]}}.  Si una verificación no se cumple, lanza una excepción. El
\code{assert} no es compilado cuando se utiliza una opción del compilador.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n}{File} \PYG{n}{f} \PYG{p}{=} \PYG{n}{open}\PYG{p}{(}\PYG{l+s}{"archivo"}\PYG{p}{)}\PYG{p}{;}
\PYG{k}{assert} \PYG{p}{(}\PYG{n}{f}\PYG{p}{.}\PYG{n}{ok}\PYG{p}{(}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
\end{Verbatim}

\item[{Diseño por contrato}] \leavevmode\\
El diseño por contrato es un concepto introducido por el lenguaje \href{http://www.eiffel.com/}{Eiffel}
a mediados/finales de los `80. Se trata de incorporar en el lenguaje las
herramientas para poder aplicar verificaciones formales a las interfaces de
los programas.

\href{http://www.digitalmars.com/d/}{D} implementa las siguientes formas de diseño por contrato (todas se
ejecutan siempre y cuando no se compile en modo \emph{release}, de manera de no
sacrificar rendimiento cuando es necesario) \hyperlink{dwcp}{{[}DWCP{]}}:
\begin{description}
\item[{Pre y post condiciones}] \leavevmode\\
Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{double} \PYG{n}{raiz\PYGZus{}cuadrada}\PYG{p}{(}\PYG{k+kt}{double} \PYG{n}{x}\PYG{p}{)}
\PYG{k}{in} \PYG{p}{\PYGZob{}} \PYG{c+c1}{// pre-condiciones}
   \PYG{k}{assert} \PYG{p}{(}\PYG{n}{x} \PYG{p}{\textgreater{}=} \PYG{l+m+mf}{0.0}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k}{out} \PYG{p}{(}\PYG{n}{resultado}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{c+c1}{// post-condiciones}
   \PYG{k}{assert} \PYG{p}{(}\PYG{n}{resultado} \PYG{p}{\textgreater{}=} \PYG{l+m+mf}{0.0}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{x} \PYG{p}{\textless{}} \PYG{l+m+mf}{1.0}\PYG{p}{)}
      \PYG{k}{assert} \PYG{p}{(}\PYG{n}{resultado} \PYG{p}{\textless{}} \PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{else} \PYG{k}{if} \PYG{p}{(}\PYG{n}{x} \PYG{p}{\textgreater{}} \PYG{l+m+mf}{1.0}\PYG{p}{)}
      \PYG{k}{assert} \PYG{p}{(}\PYG{n}{resultado} \PYG{p}{\textgreater{}} \PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{else}
      \PYG{k}{assert} \PYG{p}{(}\PYG{n}{resultado} \PYG{p}{==} \PYG{l+m+mi}{1}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\PYG{k}{body} \PYG{p}{\PYGZob{}}
   \PYG{c+c1}{// implementación}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\item[{Invariantes de representación}] \leavevmode\\
La invariante de representación es un método de una clase o estructura
que es verificada cuando se completa su construcción, antes de la
destrucción, antes y después de ejecutar cualquier función miembro
pública y cuando se lo requiere de forma explícita utilizando
\code{assert}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Fecha} \PYG{p}{\PYGZob{}}
      \PYG{k+kt}{int} \PYG{n}{dia}\PYG{p}{;}
      \PYG{k+kt}{int} \PYG{n}{hora}\PYG{p}{;}
      \PYG{k}{invariant}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}
         \PYG{k}{assert}\PYG{p}{(}\PYG{l+m+mi}{1} \PYG{p}{\textless{}=} \PYG{n}{dia} \PYG{p}{\&\&} \PYG{n}{dia} \PYG{p}{\textless{}=} \PYG{l+m+mi}{31}\PYG{p}{)}\PYG{p}{;}
         \PYG{k}{assert}\PYG{p}{(}\PYG{l+m+mi}{0} \PYG{p}{\textless{}=} \PYG{n}{hora} \PYG{p}{\&\&} \PYG{n}{hora} \PYG{p}{\textless{}} \PYG{l+m+mi}{24}\PYG{p}{)}\PYG{p}{;}
      \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\end{description}

\item[{Pruebas unitarias}] \leavevmode\\
Es posible incluir pequeñas pruebas unitarias en el lenguaje. Éstas son
ejecutadas (cuando no se compila en modo \emph{release}) al comenzar el
programa, antes de que la función \code{main()} \hyperlink{dwut}{{[}DWUT{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{unittest} \PYG{p}{\PYGZob{}}
   \PYG{n}{Fecha} \PYG{n}{fecha}\PYG{p}{;}
   \PYG{n}{fecha}\PYG{p}{.}\PYG{n}{dia} \PYG{p}{=} \PYG{l+m+mi}{5}\PYG{p}{;}
   \PYG{k}{assert} \PYG{p}{(}\PYG{n}{fecha}\PYG{p}{.}\PYG{n}{dia} \PYG{p}{==} \PYG{l+m+mi}{5}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{assert} \PYG{p}{(}\PYG{n}{fecha}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\item[{Orden de construcción estática}] \leavevmode\\
A diferencia de C++, \href{http://www.digitalmars.com/d/}{D} garantiza el orden de inicialización de los
módulos. Si bien en C++ no hay módulos si no unidades de compilación, es
posible que se ejecute código antes del \code{main()} en C++, si hay, por
ejemplo, instancias globales con un constructor definido. C++ no garantiza
un orden de inicialización, lo que trae muchos problemas. En \href{http://www.digitalmars.com/d/}{D} se define
el orden de inicialización y es el mismo orden en que el usuario importa
los módulos \hyperlink{dwmo}{{[}DWMO{]}}.

\item[{Inicialización garantizada}] \leavevmode\\
Todas las variables son inicializadas por el lenguaje (a menos que el
usuario pida explícitamente que no lo sean) \hyperlink{dwty}{{[}DWTY{]}} \hyperlink{dwvi}{{[}DWVI{]}}. Siempre que
sea posible se elijen valores de inicialización que permitan saber al
programador que la variable no fue inicializada explícitamente, de manera
de poder detectar errores de manera temprana.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{double} \PYG{n}{d}\PYG{p}{;}      \PYG{c+c1}{// inicializado a NaN}
\PYG{k+kt}{int} \PYG{n}{x}\PYG{p}{;}         \PYG{c+c1}{// inicializado a 0}
\PYG{n}{Fecha} \PYG{n}{f}\PYG{p}{;}       \PYG{c+c1}{// inicializado a null}
\PYG{k+kt}{byte}\PYG{p}{[}\PYG{l+m+mi}{5}\PYG{p}{]} \PYG{n}{a}\PYG{p}{;}     \PYG{c+c1}{// inicializados todos los valores a 0}
\PYG{k+kt}{long} \PYG{n}{l} \PYG{p}{=} \PYG{k+kt}{void}\PYG{p}{;} \PYG{c+c1}{// NO inicializado (explícitamente)}
\end{Verbatim}

\item[{\emph{RAII} (\emph{Resource Adquisition Is Initialization})}] \leavevmode\\
Es una técnica muy utilizada en C++ que consiste en reservar recursos por
medio de la construcción de un objeto y liberarlos cuando se libera éste.
Al llamarse al destructor de manera automática cuando se sale del \emph{scope},
se asegura que el recurso será liberado también.

Esta técnica es la base para desarrollar código seguro en cuanto
a excepciones (\emph{exception-safe}) \hyperlink{sutt99}{{[}SUTT99{]}}.

En \href{http://www.digitalmars.com/d/}{D} no es tan común utilizar \emph{RAII} dada la existencia del recolector de
basura (en la mayoría de los casos el recurso a administrar es
sencillamente memoria). Sin embargo en los casos en donde es necesario,
puede utilizarse \emph{RAII} mediante la utilización de la palabra reservada
\code{scope}, que limita la vida de un objeto a un bloque de código \hyperlink{dwes}{{[}DWES{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Archivo} \PYG{p}{\PYGZob{}}
   \PYG{k}{this}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{c+cm}{/* adquiere recurso */} \PYG{p}{\PYGZcb{}}
   \PYG{p}{\textasciitilde{}}\PYG{k}{this}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{c+cm}{/* libera recurso */} \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\PYG{k+kt}{void} \PYG{n}{f}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{scope} \PYG{n}{Archivo} \PYG{n}{archivo} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Archivo}\PYG{p}{;}
   \PYG{c+c1}{// uso de archivo}
\PYG{p}{\PYGZcb{}} \PYG{c+c1}{// en este punto se llama al destructor de archivo}
\end{Verbatim}

\item[{Guardias de bloque (\emph{scope guards})}] \leavevmode\\
Además de poder limitar la vida de una instancia a un \emph{scope}, es posible
especificar un bloque de código arbitrario a ejecutar al abandonar un
\emph{scope}, ya sea cuando se sale del \emph{scope} normalmente o por una falla
\hyperlink{dwes}{{[}DWES{]}}.

Ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{int} \PYG{n}{f}\PYG{p}{(}\PYG{n}{Lock} \PYG{n}{lock}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{n}{lock}\PYG{p}{.}\PYG{n}{lock}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{scope} \PYG{p}{(}\PYG{n}{exit}\PYG{p}{)}
      \PYG{n}{lock}\PYG{p}{.}\PYG{n}{unlock}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}              \PYG{c+c1}{// ejecutado siempre que salga de f()}
   \PYG{k}{auto} \PYG{n}{trans} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Transaccion}\PYG{p}{;}
   \PYG{k}{scope} \PYG{p}{(}\PYG{n}{success}\PYG{p}{)}
      \PYG{n}{trans}\PYG{p}{.}\PYG{n}{commit}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}             \PYG{c+c1}{// ejecutado si sale con "return"}
   \PYG{k}{scope} \PYG{p}{(}\PYG{n}{failure}\PYG{p}{)}
      \PYG{n}{trans}\PYG{p}{.}\PYG{n}{rollback}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}           \PYG{c+c1}{// ejecutado si sale por una excepción}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{condicion}\PYG{p}{)}
      \PYG{k}{throw} \PYG{n}{Exception}\PYG{p}{(}\PYG{l+s}{"error"}\PYG{p}{)}\PYG{p}{;}   \PYG{c+c1}{// lock.unlock() y trans.rollback()}
   \PYG{k}{else} \PYG{k}{if} \PYG{p}{(}\PYG{n}{otra\PYGZus{}condicion}\PYG{p}{)}
      \PYG{k}{return} \PYG{l+m+mi}{5}\PYG{p}{;}                   \PYG{c+c1}{// lock.unlock() y trans.commit()}
   \PYG{k}{return} \PYG{l+m+mi}{0}\PYG{p}{;}                      \PYG{c+c1}{// lock.unlock() y trans.commit()}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

Esta es una nueva forma de poder escribir código \emph{exception-safe}, aunque
el programador debe tener un poco más de cuidado de especificar las
acciones a ejecutar al finalizar el \emph{scope}.

\item[{Primitivas de sincronización de hilos}] \leavevmode\\
La programación multi-hilo está directamente soportada por el lenguaje,
y se provee una primitiva de sincronización al igual que \href{http://www.java.com/}{Java}. La palabra
reservada \code{synchronized} puede aparecer como modificador de métodos (en
cuyo caso se utiliza un \emph{lock} por clase para sincronizar) o como una
sentencia, en cuyo caso se crea un \emph{lock} global por cada bloque
\code{synchronized} a menos que se especifique sobre qué objeto realizar la
sincronización \hyperlink{dwsy}{{[}DWSY{]}}. Por ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Foo} \PYG{p}{\PYGZob{}}
   \PYG{k}{synchronized} \PYG{k+kt}{void} \PYG{n}{bar}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{c+cm}{/* cuerpo */} \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

Es equivalente a:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{class} \PYG{n}{Foo} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{void} \PYG{n}{bar}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{k}{synchronized} \PYG{p}{(}\PYG{k}{this}\PYG{p}{)} \PYG{p}{\PYGZob{}} \PYG{c+cm}{/* cuerpo */} \PYG{p}{\PYGZcb{}}
   \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

\end{description}


\section{Compiladores}

Hay, hasta el momento, 3 compiladores de \href{http://www.digitalmars.com/d/}{D} de buena calidad: \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD}, \href{http://dgcc.sourceforge.net/}{GDC}
y \href{http://www.dsource.org/projects/ldc}{LDC}.

\href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} es el compilador de referencia, escrito por \href{http://www.walterbright.com/}{Walter Bright}. El
\emph{front-end} \footnote{
\emph{Front-end} es la parte del compilador encargada de hacer el
análisis léxico, sintáctico y semántico del código fuente, generando una
representación intermedia que luego el \emph{back-end} convierte a código de
máquina.
} de este compilador ha sido liberado bajo licencia
\href{http://www.artisticlicence.com/}{Artistic}/\href{http://www.gnu.org/copyleft/gpl.html}{GPL} y es utilizado por los otros dos compiladores, por lo tanto en
realidad hay solo un compilador disponible con 3 \emph{back-ends} \footnote{
El \emph{back-end} es la parte del compilador encargada de convertir
la representación intermedia generada por el \emph{front-end} a código de
máquina.
}
diferentes.

Con \href{http://www.digitalmars.com/d/1.0/changelog.html\#new1\_041}{DMD 1.041} se publicó el código fuente completo del compilador, pero
con una licencia muy restrictiva para uso personal, por lo que el único efecto
logrado por esto es que la gente pueda mandar parches o correcciones del
compilador pero no lo convierte en \href{http://www.gnu.org/philosophy/free-sw.es.html}{Software Libre}, siendo el único de los
3 compiladores que no tiene esta característica.

El compilador \href{http://dgcc.sourceforge.net/}{GDC} es el \emph{front-end} de \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} utilizando al compilador \href{http://gcc.gnu.org/}{GCC}
como \emph{back-end}. Fue un muy buen compilador pero estuvo abandonado por casi
tres años. A mediados de este año recibió un nuevo impulso y de a poco se está
poniendo al día con los \emph{front-ends} actuales de \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} 1.0 y 2.0, aunque la
versión 2.0 viene bastante más rezagada y todavía no es una alternativa viable
a \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD}.

\href{http://www.dsource.org/projects/ldc}{LDC} sufrió una suerte similar, es un compilador joven que utiliza como
\emph{back-end} a \href{http://llvm.org/}{LLVM} (una infraestructura modera para construir compiladores),
nacido a mediados de 2007 como un proyecto personal y privado de Tomas
Lindquist Olsen, que estuvo trabajando de forma privada en el proyecto hasta
mediados de 2008, momento en que decide publicar el código mediante una
licencia libre.  Para ese entonces el compilador era todavía inestable
y faltaban implementar varias cosas, pero el estado era lo suficientemente
bueno como para captar varios colaboradores muy capaces, como \href{http://www.ckamm.de/}{Christian
Kamm} y Frits Van Bommel que rápidamente se convirtieron en parte fundamental
del proyecto. El primer \emph{release} (0.9) de una versión relativamente completa
y estable fue a principios de 2009 que fue seguido por la versión 0.9.1 que
como puntos más salientes agregó soporte para x86-64 y assembly embebido. El
compilador tuvo un crecimiento excepcional pero estuvo muy inactivo por algún
tiempo y, si bien sigue siendo mantenido, en general los nuevos \emph{front-end} de
\href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} llevan tiempo de integrar y no está al día con el \emph{back-end} de \href{http://llvm.org/}{LLVM}
(por ejemplo desde que se actualizó para utilizar \href{http://llvm.org/}{LLVM} 2.7 que perdió la
capacidad de generar símbolos de depuración).

Además de estos compiladores hay varios otros experimentales, pero ninguno de
ellos de calidad suficiente todavía. Por ejemplo hay un compilador
experimental que emite \emph{CIL} (\emph{Common Intermediate Language}), el \emph{bytecode}
de \href{http://msdn.microsoft.com/netframework/}{.NET}, llamado \href{http://dnet.codeplex.com/}{DNet}. También hay un \emph{front-end} escrito en \href{http://www.digitalmars.com/d/}{D}, llamado
\href{http://code.google.com/p/dil/}{Dil}.

Originalmente, dado que \href{http://dgcc.sourceforge.net/}{GDC} estaba siendo mantenido y que \href{http://www.dsource.org/projects/ldc}{LDC} no existía,
este trabajo iba a ser realizado utilizando \href{http://dgcc.sourceforge.net/}{GDC} como compilador, dado que al
ser \href{http://www.gnu.org/philosophy/free-sw.es.html}{Software Libre} podía ser modificado de ser necesario. Pero finalmente,
dada la poca confiabilidad que presenta la continuidad del desarrollo de tanto
\href{http://dgcc.sourceforge.net/}{GDC} como \href{http://www.dsource.org/projects/ldc}{LDC}, y que el código de \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} está disponible en su totalidad
(aunque no sea \href{http://www.gnu.org/philosophy/free-sw.es.html}{Software Libre} por completo), se optó por utilizar este
último, dado que es la implementación de referencia que fue más constantemente
mantenida y desarrollada.

\resetcurrentobjects
\hypertarget{--doc-gc}{}

\hypertarget{gc}{}\chapter{Recolección de basura}


\hypertarget{gc-intro}{}\section{Introducción}

\emph{Recolección de basura} se refiere a la recuperación automática de memoria del
\emph{heap} \footnote{
\emph{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 \emph{stack}, la duración de la \emph{reserva} no está
atada a un bloque de código.
} 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 \hyperlink{joli96}{{[}JOLI96{]}}. En particular, al
diseñar o programar bibliotecas, de no haber un recolector de basura, \textbf{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 \emph{buffer
overflows} \footnote{
Un \emph{buffer overflow} (\emph{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.
} o \emph{dangling pointers} \footnote{
Un \emph{dangling pointer} (\emph{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 re-asignada para almacenar otro objeto.
}) son la causa más
frecuente de problemas de seguridad \hyperlink{bezo06}{{[}BEZO06{]}}.

La recolección de basura nació junto a \href{http://www.lisp.org/}{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
\href{http://www.java.com/}{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
el rendimiento 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 aplicaciones
con altos requerimientos de rendimiento. En la actualidad un programa que
utiliza un recolector moderno puede ser comparable en rendimiento 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 \footnote{
Localidad de referencia es la medida en que los accesos
sucesivos de memoria cercana espacialmente son cercanos también en el
tiempo. Por ejemplo, un programa que lee todos los elementos de una matriz
contigua de una vez o que utiliza la misma variable repetidamente tiene
buena localidad referencia. Una buena localidad de referencia interactúa
bien con la memoria virtual y caché, ya que reduce el conjunto de trabajo
(o \emph{working set}) y mejora la probabildad de éxito (\emph{hit rate}).
}, 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 de
basura, éste se vuelve más un problema que una solución, porque 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.


\hypertarget{gc-intro-basics}{}\subsection{Conceptos básicos}

Los programas pueden hacer uso principalmente de 4 áreas de memoria:
\begin{description}
\item[{Registros}] \leavevmode\\
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.

\item[{Área de memoria estática}] \leavevmode\\
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: \textbf{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).

\item[{\emph{Stack} (pila)}] \leavevmode\\
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 \hyperlink{joli96}{{[}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
\footnote{
En general en la literatura se nombra a una porción de
memoria asignada individualmente \emph{celda}, \emph{nodo} u \emph{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).
} asignada antes que otra nunca puede ser liberada antes que
aquella.

\item[{\emph{Heap}}] \leavevmode\\
A diferencia del \emph{stack}, el \emph{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.

\end{description}

La recolección de basura impone algunas restricciones sobre la manera de
utilizar el \emph{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 \emph{stack} (normalmente denominado \emph{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 \emph{root set}. Por lo tanto, una celda está \emph{viva} si y sólo si su dirección
de memoria está almacenada en una celda \emph{raíz} (parte del \emph{root set}) o si
está almacenada en otra celda \emph{viva} del \emph{heap}.

Cabe aclarar que esta es una definición conceptual, asumiendo que el programa
siempre limpia una dirección de memoria almacenada en el \emph{root set} o una
celda del \emph{heap} cuando la celda a la que apunta no va a ser utilizada
nuevamente. Esto no es siempre cierto y los \emph{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 \emph{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 diferencia entre dos partes
del programa, el recolector de basura y el programa en sí. A la primera se la
suele denominar simplemente \emph{recolector} y a la segunda \emph{mutator}, dado que es
la única que modifica (o \emph{muta}) el grafo de conectividad.
\hypertarget{gc-intro-mark}{}

\subsection{Recorrido del grafo de conectividad}

El problema de encontrar las celdas \emph{vivas} de un programa se reduce
a recorrer un grafo dirigido. El grafo se define como:
\begin{gather}
\begin{split}G = (V,A)\end{split}\notag
\end{gather}
Donde $V$ es el conjunto de vértices, dado por las celdas de memoria
y $A$ es un conjunto de pares ordenados (aristas), dado por la relación
$M \rightarrow N$ (es decir, los punteros).

El grafo comienza a recorrerse desde el \emph{root set} y todos los vértices que
fueron visitados componen el \emph{live set}; el resto de los vértices son
\emph{basura}.

Más formalmente, Definimos:
\begin{description}
\item[{\emph{Camino}}] \leavevmode\\
Es una 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
\emph{vértice inicial} y un \emph{vértice final} (llamados en conjunto \emph{vértices
terminales}).  Cualquier vértice no terminal es denominado \emph{vértice
interior}.
\begin{gather}
\begin{split}\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\end{split}\notag
\end{gather}
Un camino cuyos \emph{vértices terminales} coinciden, es decir $v_1
= v_N$, es denominado \textbf{Ciclo}. Cabe notar que los \emph{vértices terminales}
de un ciclo son completamente arbitrarios, ya que cualquier \emph{vértice
interior} puede ser un \emph{vértice terminal}.

\item[{\emph{Conexión}}] \leavevmode\\
Decimos que $M$ está \emph{conectado} a $N$ si y sólo si existe un
camino de $M$ a $N$.
\begin{gather}
\begin{split}M \mapsto N \Longleftrightarrow \exists \underset{M \to N}{C} \in G\end{split}\notag
\end{gather}
\item[{\emph{Live set}}] \leavevmode\\
Es el conjunto de celdas \emph{vivas} está dado por todos los vértices
($v$) del grafo para los cuales existe una raíz en el \emph{root set} que
esté conectada a él.
\begin{gather}
\begin{split}Live \thickspace set = \left\lbrace v \in V \big/
   \left( \exists r \in Root \thickspace set \big/ r \mapsto v \right)
\right\rbrace\end{split}\notag
\end{gather}
\item[{\emph{Basura}}] \leavevmode\\
La basura, o celdas \emph{muertas}, quedan determinadas entonces por todas las
celdas del \emph{heap} que no son parte del \emph{live set}.
\begin{gather}
\begin{split}Basura = V - Live \thickspace set\end{split}\notag
\end{gather}
\end{description}

El \emph{Live set} y la \emph{Basura} conforman una partición del \emph{heap} (ver figura
\vref{fig:gc-heap-parts}).
\begin{figure}[btp]
\centering
\includegraphics{graphviz-152dd7a8642215dea3e09531c3bb69e2f55bc6ed.pdf}\caption[Distintas partes de la memoria \emph{heap}]{Distintas partes de la memoria, incluyendo relación entre \emph{basura}, \emph{live
set}, \emph{heap} y \emph{root set}.}
\label{fig:gc-heap-parts}
\end{figure}


Al proceso de visitar los vértices \emph{conectados} desde el \emph{root set} se lo
denomina \emph{marcado}, \emph{fase de marcado} o \emph{mark phase} en inglés, debido a que
es necesario marcar los vértices para evitar visitar dos veces el mismo nodo
en casos en los que el grafo contenga ciclos. De forma similar a la búsqueda,
que puede realizarse \emph{primero a lo ancho} (\emph{breadth-first}) o \emph{primero a lo
alto} (\emph{depth-first}) del grafo, el marcado de un grafo también puede
realizarse de ambas maneras. Cada una podrá o no tener efectos en el
rendimiento, en particular dependiendo de la aplicación puede convenir uno
u otro método para lograr una mejor localidad de referencia.

Un algoritmo simple (recursivo) de marcado \emph{primero a lo alto} puede ser el
siguiente (asumiendo que partimos con todos los vértices sin marcar)
\footnote{
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, \code{r*} denota una referencia o puntero y \code{*r}
denota ``objeto al que apunta \code{r}``. Se sobreentiende que \code{r = o}
siempre toma la dirección de memoria de \code{o}.
}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark}\PYG{p}{(}\PYG{n}{v}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{if} \PYG{k}{not} \PYG{n}{v}\PYG{p}{.}\PYG{n}{marked}
      \PYG{n}{v}\PYG{p}{.}\PYG{n}{marked} \PYG{o}{=} \PYG{n+nb}{true}
      \PYG{k}{foreach} \PYG{p}{(}\PYG{n}{src}\PYG{p}{,} \PYG{n}{dst}\PYG{p}{)} \PYG{k}{in} \PYG{n}{v}\PYG{p}{.}\PYG{n}{edges}
         \PYG{n}{mark}\PYG{p}{(}\PYG{n}{dst}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{r} \PYG{k}{in} \PYG{n}{root\PYGZus{}set}
      \PYG{n}{mark}\PYG{p}{(}\PYG{n}{r}\PYG{p}{)}
\end{Verbatim}

Una vez concluido el marcado, sabemos que todos los vértices con la marca son
parte del \emph{live set} y que todos los vértices no marcados son \emph{basura}.  Esto
es conocido también como \textbf{abstracción bicolor}, dado que en la literatura se
habla muchas veces de \emph{colorear} las celdas. En general, una celda sin marcar
es de color blanco y una marcada de color negro.

Puede observarse un ejemplo del algoritmo en la figura \vref{fig:gc-mark-1},
en la cual se marca el sub-grafo apuntando por \code{r0}. Luego se marca el
sub-grafo al que apunta \code{r1} (ver figura \vref{fig:gc-mark-2}), concluyendo
con el marcado del grafo completo, dejando sin marcar solamente las celdas
\emph{basura} (en blanco).
\begin{figure}[btp]
\centering
\subfloat[Se comienza a marcar el grafo por la raíz r0.]{\includegraphics{graphviz-15aae074c43636f4b282f7ab12746165f7ad1e50.pdf}}
\hspace{0.1in}
\subfloat[Luego de marcar el nodo \code{h1}, se procede al \code{h2}.]{\includegraphics{graphviz-f2c3351c20ac022f0ff3bc129e053fe628276a87.pdf}}
\hspace{0.1in}
\subfloat[Luego sigue el nodo h5.]{\includegraphics{graphviz-e1cc5b6d0acdab6017bfc398e64c1f3d54224dee.pdf}}
\caption[Ejemplo de marcado del grafo de conectividad (parte 1)]{Ejemplo de marcado del grafo de conectividad (parte 1).}
\label{fig:gc-mark-1}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[El nodo h5 tiene una arista al h1, pero el h1 ya fue visitado, por lo
tanto no se visita nuevamente.]{\includegraphics{graphviz-12d2ff465e37c98058b37d10c930259f90df5b34.pdf}}
\hspace{0.1in}
\subfloat[Se concluye el marcado del sub-grafo al que conecta r0, se procede
a marcar el sub-grafo al que conecta r1, marcando al nodo h6.]{\includegraphics{graphviz-3b5965cb3680165d978edad39cc1a92dbf4d0e47.pdf}}
\hspace{0.1in}
\subfloat[El nodo h6 tiene una arista al h2, pero éste ya fue marcado por lo
que no se vuelve a visitar. No hay más raíces, se finaliza el marcado
del grafo.]{\includegraphics{graphviz-b512a457a176540f37f35685b8e172b3b0128a4c.pdf}}
\caption[Ejemplo de marcado del grafo de conectividad (parte 2)]{Ejemplo de marcado del grafo de conectividad (parte 2).}
\label{fig:gc-mark-2}
\end{figure}

\hypertarget{gc-intro-tricolor}{}

\subsection{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 \hyperlink{gc-concurrent}{\emph{concurrentes}} e \hyperlink{gc-inc}{\emph{incrementales}}, además de otro tipo de optimizaciones.  Entonces, lo que plantea
esta abstracción es una nueva partición del heap al momento de marcar, esta
vez son tres porciones: blanca, gris y negra.

Al principio todas las celdas se pintan de blanco, excepto el \emph{root set} que
se pinta 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 \emph{live set} y las celdas blancas \emph{basura}. Esto se debe a que
siempre se mantiene esta invariante: \textbf{ninguna celda negra apunta directamente
a una celda blanca} (considerando como atómica la operación de pintar una
celda de negro y a sus hijas directas de gris). 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 \emph{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):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{r} \PYG{k}{in} \PYG{n}{root\PYGZus{}set}
      \PYG{n}{gray\PYGZus{}set}\PYG{p}{.}\PYG{n}{add}\PYG{p}{(}\PYG{n}{r}\PYG{p}{)}
   \PYG{k}{while} \PYG{k}{not} \PYG{n}{gray\PYGZus{}set}\PYG{p}{.}\PYG{n}{empty}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{v} \PYG{o}{=} \PYG{n}{gray\PYGZus{}set}\PYG{p}{.}\PYG{n}{pop}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{black\PYGZus{}set}\PYG{p}{.}\PYG{n}{add}\PYG{p}{(}\PYG{n}{v}\PYG{p}{)}
      \PYG{k}{foreach} \PYG{p}{(}\PYG{n}{src}\PYG{p}{,} \PYG{n}{dst}\PYG{p}{)} \PYG{k}{in} \PYG{n}{v}\PYG{p}{.}\PYG{n}{edges}
         \PYG{k}{if} \PYG{n}{dst} \PYG{k}{in} \PYG{n}{white\PYGZus{}set}
            \PYG{n}{white\PYGZus{}set}\PYG{p}{.}\PYG{n}{remove}\PYG{p}{(}\PYG{n}{dst}\PYG{p}{)}
            \PYG{n}{gray\PYGZus{}set}\PYG{p}{.}\PYG{n}{add}\PYG{p}{(}\PYG{n}{dst}\PYG{p}{)}
\end{Verbatim}

Si bien este algoritmo no es recursivo, tiene un requerimiento de espacio
$O(\lvert Live \thickspace set \rvert)$. Un ejemplo donde se aprecia
esto a simple vista es cuando el \emph{Live set} resulta una lista simplemente
enlazada, en cuyo caso el \emph{gray\_set} deberá almacenar todos los nodos del
\emph{Live set}.
\hypertarget{gc-intro-services}{}

\subsection{Servicios}

En general todos los algoritmos de recolección de basura utilizan servicios de
una capa inferior \footnote{
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 \emph{low level allocator} en inglés).
} y proveen servicios a una capa superior
\footnote{
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.
}.

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:
\begin{description}
\item[{$alloc() \to cell$}] \leavevmode\\
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 (\code{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 \emph{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).

\item[{$free(cell)$}] \leavevmode\\
Libera una celda que ya no va a ser utilizada. La celda liberada debe haber
sido obtenida mediante \code{alloc()}.

\end{description}

Y los servicios básicos proporcionados por el recolector son los siguientes:
\begin{description}
\item[{$new() \to cell$}] \leavevmode\\
Obtiene una celda de memoria para ser utilizada por el programa.

\item[{$update(ref, cell)$}] \leavevmode\\
Notifica al recolector que la referencia $ref$ ahora apunta
a $cell$. Visto más formalmente, sería análogo a decir que hubo un
cambio en la conectividad del grafo: la arista $src \to old$ cambia
por $src \to new$ (donde $src$ es la celda que contiene la
referencia $ref$, $old$ es la celda a la que apunta la
referencia $ref$ y $new$ es el argumento $cell$). Si
$cell$ es \code{null}, sería análogo a informar que se elimina la arista
$src \to old$.

\item[{$del(cell)$}] \leavevmode\\
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 $update(ref, null)$ pero sin proporcionar información sobre la
arista a eliminar). Esto es generalmente útil solo en \hyperlink{gc-rc}{\emph{conteo de
referencias}}. 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 $\big\lbrace (v, w) \in A , v \in
Live \thickspace set , w \in Live \thickspace set \big/ w = cell
\big\rbrace$.

\item[{$collect()$}] \leavevmode\\
Este servicio indica al recolector que debe hacer un análisis del grafo de
conectividad en busca de \emph{basura}. Generalmente este servicio es invocado
por el propio recolector cuando no hay más celdas reciclables.

\end{description}

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.
\hypertarget{gc-classic}{}

\section{Algoritmos clásicos}

En la literatura se encuentran normalmente referencias a tres 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.


\hypertarget{gc-rc}{}\subsection{Conteo de referencias}

Se trata del algoritmo más antiguo de todos, implementado por primera vez por
\href{http://en.wikipedia.org/wiki/John\_McCarthy\_\%28computer\_scientist\%29}{John McCarthy} para \href{http://www.lisp.org/}{Lisp} a finales de 1950. Se trata de un método
\hyperlink{gc-direct}{\emph{directo}} e \hyperlink{gc-inc}{\emph{incremental}} por naturaleza, ya
que distribuye la carga de la recolección de basura durante toda la ejecución
del programa, cada vez que el \emph{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 \textbf{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 $rc(v)$ (de \emph{reference counter} en inglés)
de la siguiente manera:
\begin{gather}
\begin{split}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\end{split}\notag
\end{gather}
El \emph{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 \emph{mutator} no tiene ninguna referencia a la
celda y por lo tanto es \emph{basura}:
\begin{gather}
\begin{split}rc(v) = 0 \Rightarrow v \in Basura\end{split}\notag
\end{gather}
Para mantener esta invariante el \emph{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 \emph{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 $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):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{cell} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{cell} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{throw} \PYG{n}{out\PYGZus{}of\PYGZus{}memory}
   \PYG{n}{cell}\PYG{p}{.}\PYG{n}{rc} \PYG{o}{=} \PYG{l+m+mi}{1}
   \PYG{k}{return} \PYG{n}{cell}

\PYG{k}{function} \PYG{n}{del}\PYG{p}{(}\PYG{n}{cell}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{cell}\PYG{p}{.}\PYG{n}{rc} \PYG{o}{=} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{rc} \PYG{o}{-} \PYG{l+m+mi}{1}
   \PYG{k}{if} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{rc} \PYG{k}{is} \PYG{l+m+mi}{0}
      \PYG{k}{foreach} \PYG{n}{child}\PYG{o}{*} \PYG{k}{in} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{children}
         \PYG{n}{del}\PYG{p}{(}\PYG{o}{*}\PYG{n}{child}\PYG{p}{)}
      \PYG{n}{free}\PYG{p}{(}\PYG{n}{cell}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{update}\PYG{p}{(}\PYG{n}{ref}\PYG{o}{*}\PYG{p}{,} \PYG{n}{cell}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{cell}\PYG{p}{.}\PYG{n}{rc} \PYG{o}{=} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{rc} \PYG{o}{+} \PYG{l+m+mi}{1}
   \PYG{n}{del}\PYG{p}{(}\PYG{o}{*}\PYG{n}{ref}\PYG{p}{)}
   \PYG{o}{*}\PYG{n}{ref} \PYG{o}{=} \PYG{n}{cell}
\end{Verbatim}


\hypertarget{gc-rc-cycles}{}\subsubsection{Ciclos}

El conteo de referencias tiene, sin embargo, un problema fundamental: \textbf{falla
con estructuras cíclicas}. Esto significa que siempre que haya un ciclo en el
grafo de conectividad, hay una pérdida de memoria potencial en el programa.

Cuando esto sucede, las celdas que participan del ciclo tienen siempre su
contador mayor que 0, sin embargo puede suceder que ningún elemento del \emph{root
set} apunte a una celda dentro del ciclo, por lo tanto el ciclo es \emph{basura}
(al igual que cualquier otra celda para la cual hayan referencias desde el
ciclo pero que no tenga otras referencias externas) y sin embargo los
contadores no son 0. Los ciclos, por lo tanto, violan la invariante del conteo
de referencia.

Hay formas de solucionar esto, pero siempre recaen en un esquema que va por
fuera del conteo de referencias puro. En general los métodos para solucionar
esto son variados y van desde realizar un marcado del sub-grafo para detectar
ciclos y liberarlos hasta tener otro recolector completo de \emph{emergencia};
pasando por tratar los ciclos como un todo para contar las referencias al
ciclo completo en vez de a cada celda en particular.

Incluso con este problema, el conteo de referencia sin ningún tipo de solución
en cuanto a la detección y recolección de ciclos fue utilizado en muchos
lenguajes de programación sin que su necesidad sea tan evidente. Por ejemplo
\href{http://www.python.org/}{Python} agregó recolección de ciclos en la versión 2.0 \hyperlink{nas00}{{[}NAS00{]}} (liberada en
octubre de 2000) y \href{http://www.php.net/}{PHP} recién agrega detección de ciclos en la versión 5.3
\hyperlink{php530}{{[}PHP530{]}}.
\hypertarget{gc-rc-example}{}

\subsubsection{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, \code{left} (\code{l}) y \code{right} (\code{r}) y se muestra el contador de
referencias abajo del nombre de cada celda. Se parte con una pequeña
estructura ya construida y se muestra como opera el algoritmo al eliminar
o cambiar una referencia (cambios en la conectividad del grafo). En un
comienzo todas las celdas son accesibles desde el \emph{root set} por lo tanto son
todas parte del \emph{live set}.

Se comienza por eliminar la referencia de \code{r0} a \code{h1}, que determina que
\code{h1} se convirtió en \emph{basura} (ver figura \vref{fig:gc-rc-rm-1}). Esto
conduce al decremento del contador de \code{h2} y \code{h3} que permanecen en el
\emph{live set} ya que sus contadores siguen siendo mayores a 0 (ver figura
\vref{fig:gc-rc-rm-2}).
\begin{figure}[btp]
\centering
\subfloat[Estado inicial del grafo de conectividad.]{\includegraphics{graphviz-086baa74cf93c6c380991274084e89c41053a80d.pdf}}
\hspace{0.1in}
\subfloat[Al ejecutarse \code{update(r0, null)}, se comienza por visitar la celda
\code{h1}.]{\includegraphics{graphviz-f651b7c8fbdbb31e53ea8c9300c36971d0c14432.pdf}}
\hspace{0.1in}
\subfloat[Se decrementa el contador de \code{h1} quedando en 0 (pasa a ser \emph{basura}).
Se elimina primero \code{h1.l} y luego \code{h1.r}.]{\includegraphics{graphviz-8e57385e18038eba84d702890d93b80debccb1e5.pdf}}
\caption[Ejemplo de conteo de referencias: eliminación de una referencia (parte 1)]{Eliminación de la referencia \code{r0} $\to$ \code{h1} (parte 1).}
\label{fig:gc-rc-rm-1}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Se decrementa el contador de \code{h2} pero no queda en 0 (permanece en el
\emph{live set}).]{\includegraphics{graphviz-9b5c4c8ae0bece6a158936f7fc69bad8f29e4846.pdf}}
\hspace{0.5in}
\subfloat[El contador de \code{h3} tampoco queda en 0, sigue en el \emph{live set}.]{\includegraphics{graphviz-bdc3515ea6e943cf137f3ca58f974c6979bea49c.pdf}}
\caption[Ejemplo de conteo de referencias: eliminación de una referencia (parte 2)]{Eliminación de la referencia \code{r0} $\to$ \code{h1} (parte 2).}
\label{fig:gc-rc-rm-2}
\end{figure}


Luego se cambia una referencia (en vez de eliminarse) realizándose la
operación \code{update(h3.l, h5)}. Para esto primero se incrementa el contador de
referencias de \code{h5} para evitar confundirlo accidentalmente con \emph{basura} si
se elimina alguna celda que apuntaba a ésta. Luego se procede a decrementar el
contador de \code{h2} que queda en 0, transformándose en \emph{basura} (ver figura
\vref{fig:gc-rc-up-1}).
\begin{figure}[btp]
\centering
\subfloat[Comienza \code{update(h3.l, h5)}, se incrementa el contador de \code{h5}.]{\includegraphics{graphviz-022c65fb00c8667cb05cb205e54a4c42aa683d6d.pdf}}
\hspace{0.1in}
\subfloat[Luego se procede a visitar la antigua referencia de \code{h3.l} (\code{h2}).]{\includegraphics{graphviz-07af48a68c9720f17f81dfc4c84f56c6e3ae8450.pdf}}
\hspace{0.1in}
\subfloat[Se decrementa el contador de \code{h2} y queda en 0 (pasa a ser \emph{basura}).
Se eliminan las referencias a las hijas.]{\includegraphics{graphviz-9c433c864d73935e21ced92476e6b85a2b257e3e.pdf}}
\caption[Ejemplo de conteo de referencias: actualización de una referencia (parte 1)]{Cambio en la referencia \code{h3.l} $\to$ \code{h2} a \code{h3.l} $\to$
\code{h5} (parte 1).}
\label{fig:gc-rc-up-1}
\end{figure}


Lo mismo pasa cuando se desciende a \code{h4}, pero al descender a \code{h5}
y decrementar el contador, éste sigue siendo mayor que 0 (pues \code{h3} va
a apuntar a \code{h5}) así que permanece en el \emph{live set}. Finalmente se termina
de actualizar la referencia \code{h3.l} para que apunte a \code{h5} (ver figura
\vref{fig:gc-rc-up-2}).
\begin{figure}[btp]
\centering
\subfloat[Se decrementa el contador de \code{h4} quedando en 0, pasa a ser \emph{basura}.
Se continúa con \code{h5}.]{\includegraphics{graphviz-0624e7936777f5daa630825b848f6593abe74b68.pdf}}
\hspace{0.1in}
\subfloat[Se decrementa el contador de \code{h5} pero sigue siendo mayor que 0.]{\includegraphics{graphviz-d6e6f36cd3d48bc4348ce0e93070957a3b6f0175.pdf}}
\hspace{0.1in}
\subfloat[Se termina por actualizar la referencia de \code{h3.l} para que apunte
a \code{h5}.]{\includegraphics{graphviz-bf57fef91e494749aa936212c935ed8e04c6e5d6.pdf}}
\caption[Ejemplo de conteo de referencias: actualización de una referencia (parte 2)]{Cambio en la referencia \code{h3.l} $\to$ \code{h2} a \code{h3.l} $\to$
\code{h5} (parte 2).}
\label{fig:gc-rc-up-2}
\end{figure}


Finalmente se presenta lo que sucede cuando se elimina la última referencia
a un ciclo (en este caso un ciclo simple de 2 celdas: \code{h3} y \code{h6}). Se
elimina la única referencia externa al ciclo (\code{r1}), por lo que se visita la
celda \code{h3} decrementando su contador de referencias, pero éste continúa
siendo mayor que 0 porque la celda \code{h6} (parte del ciclo) la referencia. Por
lo tanto el ciclo, y todas las celdas a las que apunta que no tienen otras
referencias externas y por lo tanto deberían ser \emph{basura} también (\code{h5}), no
pueden ser recicladas y su memoria es perdida (ver figura
\vref{fig:gc-rc-cycle}).
\begin{figure}[btp]
\centering
\subfloat[El ejecutarse \code{update(r1, null)} se visita la celda \code{h3}.]{\includegraphics{graphviz-d50c06852b5fcec0767767a1712786d768ad0b05.pdf}}
\hspace{0.5in}
\subfloat[Se decrementa el contador de \code{h3} pero sigue siendo mayor que 0 por el
ciclo.]{\includegraphics{graphviz-33c8b08eba1976dc56c3b69e18fb1ce1b47638c9.pdf}}
\caption[Ejemplo de conteo de referencias: pérdida de memoria debido a un ciclo]{Eliminación de la referencia \code{r1} $\to$ \code{h3} (pérdida de memoria
debido a un ciclo).}
\label{fig:gc-rc-cycle}
\end{figure}

\hypertarget{gc-mark-sweep}{}

\subsection{Marcado y barrido}

Este algoritmo es el más parecido a la teoría sobre recolección de basura.
Consiste en realizar la recolección en 2 fases: marcado y barrido. La primera
fase consiste en el proceso de marcar el grafo de conectividad del \emph{heap} para
descubrir qué celdas son alcanzables desde el \emph{root set}, tal y como se
describió en \hyperlink{gc-intro-mark}{\emph{Recorrido del grafo de conectividad}}.

Una vez marcadas todas las celdas, se sabe que las celdas \emph{blancas} son
\emph{basura}, por lo tanto el paso que queda es el \emph{barrido} de estas celdas,
liberándolas. Esto se efectúa recorriendo todo el \emph{heap}. Por lo tanto cada
recolección es $O(\lvert Heap \rvert)$, a diferencia del conteo de
referencia que dijimos que en el peor caso es $O(\lvert Live \thickspace
set \rvert)$. Sin embargo el conteo de referencias se ejecuta \textbf{cada vez que
se actualiza una referencia} mientras que la recolección en el marcado
y barrido se realiza típicamente solo cuando el \emph{mutator} pide una celda pero
no hay ninguna libre. Esto hace que la constante del conteo de referencias sea
típicamente varios órdenes de magnitud mayores que en el marcado y barrido.

A continuación se presentan los servicios básicos de este algoritmo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{cell} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{cell} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{cell} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{cell} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{throw} \PYG{n}{out\PYGZus{}of\PYGZus{}memory}
   \PYG{k}{return} \PYG{n}{cell}

\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{sweep\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{sweep\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{cell} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{if} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{marked}
         \PYG{n}{cell}\PYG{p}{.}\PYG{n}{marked} \PYG{o}{=} \PYG{n+nb}{false}
      \PYG{k}{else}
         \PYG{n}{free}\PYG{p}{(}\PYG{n}{cell}\PYG{p}{)}
\end{Verbatim}

El algoritmo \code{mark\_sweep()} es exactamente igual al presentado en
\hyperlink{gc-intro-mark}{\emph{Recorrido del grafo de conectividad}}. Es preciso notar que la fase de barrido
(\code{sweep\_phase()}) debe tener una comunicación extra con el \emph{low level
allocator} para poder obtener todas las celdas de memoria que existen en el
\emph{heap}.

A diferencia del conteo de referencias, este algoritmo es \hyperlink{gc-direct}{\emph{indirecto}} y \hyperlink{gc-inc}{\emph{no incremental}}, ya que se realiza un recorrido
de todo el \emph{heap} de forma espaciada a través de la ejecución del programa. En
general el \emph{mutator} sufre pausas considerablemente mayores (en promedio) que
con el conteo de referencias, lo que puede ser problemático para aplicaciones
con requerimientos rígidos de tiempo, como aplicaciones \emph{real-time}. Debido
a la percepción de las pausas grandes, este tipo de colectores se conocen como
\hyperlink{gc-concurrent}{\emph{stop-the-world}} (o \emph{detener el mundo}).

Una ventaja fundamental sobre el conteo de referencias es la posibilidad de
reclamar estructuras cíclicas sin consideraciones especiales. Podemos observar
como esto es posible analizando el ejemplo en las figuras \ref{fig:gc-mark-1}
y \vref{fig:gc-mark-2}. Si se eliminaran las referencias $r0 \to h1$
y $h6 \to h2$, la fase de marcado consistiría solamente en marcar la
celda $h6$, pues es la única alcanzable desde el \emph{root set}. Todas las
demás celdas permanecerían blancas y por lo tanto pueden ser liberadas sin
inconvenientes en la fase de barrido, que recorre el \emph{heap} linealmente.
\hypertarget{gc-copy}{}

\subsection{Copia de semi-espacio}

Este algoritmo consiste en hacer una partición del \emph{heap} en 2 mitades
o \emph{semi-espacios}, llamados usualmente \emph{Fromspace} y \emph{Tospace}. El primero se
utiliza para asignar nuevas celdas de forma lineal, asumiendo un \emph{heap}
contiguo, incrementando un puntero (ver figura \vref{fig:gc-copy}).  Esto se
conoce como \emph{pointer bump allocation} y es, probablemente, la forma más
eficiente de asignar memoria (tan eficiente como asignar memoria en el
\emph{stack}). Esto permite además evitar el problema de la \emph{fragmentación} de
memoria \footnote{
La \emph{fragmentación} de memoria sucede cuando se asignan objetos
de distintos tamaños y luego libera alguno intermedio, produciendo
\emph{huecos}. Estos \emph{huecos} quedan inutilizables hasta que se quiera
asignar un nuevo objeto de tamaño igual al \emph{hueco} (o menor). Si esto no
sucede y se acumulan muchos \emph{huecos} se dice que la memoria está
\emph{fragmentada}.
} que normalmente afectan a los otros algoritmos clásicos (o
sus \emph{low level allocators}).
\begin{figure}[btp]
\centering

\includegraphics{aafig-aa973f3370df251cc75f769f676d7cff5aed0186.pdf}
\caption[Estructura del \emph{heap} de un recolector con copia de semi-espacios]{Estructura del \emph{heap} de un recolector con copia de semi-espacios.}
\label{fig:gc-copy}
\end{figure}


La segunda mitad (\emph{Tospace}) permanece inutilizada hasta que se agota el
espacio en el \emph{Fromspace}; en ese momento comienza el proceso de recolección
de basura que consiste en recorrer el grafo de conectividad, copiando las
celdas \emph{vivas} del \emph{Fromspace} al \emph{Tospace} de manera contigua, como si
estuvieran asignando 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 \emph{vivas}. Para esto se almacena una dirección de memoria de
re-dirección, \emph{forwarding address}, en las celdas que mueven. La \emph{forwarding
address} sirve a su vez de marca, para no recorrer una celda dos veces (como
se explica en \hyperlink{gc-intro-mark}{\emph{Recorrido del grafo de conectividad}}). 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 \emph{forwarding
address}. Una vez finalizado este proceso, el \emph{Fromspace} y \emph{Tospace}
invierten roles y se prosigue de la misma manera (todo lo que quedó en el
viejo \emph{Fromspace} es \emph{basura} por definición, por lo que se convierte el
\emph{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
recolectores deben estar íntimamente relacionados con el \emph{low level
allocator}, ya que la organización del \emph{heap} y la forma de asignar memoria es
parte fundamental de este algoritmo. Se asume que ya hay dos áreas de memoria
del mismo tamaño destinadas al \emph{Fromspace} y \emph{Tospace}, y la existencia de
4 variables globales: \code{fromspace} (que apunta a la base del \emph{Fromspace}),
\code{tospace} (que apunta a la base del \emph{Tospace}), \code{spacesize} (que contiene
el tamaño de un semi-espacio) y \code{free} (que apunta al lugar del \emph{Fromspace}
donde comienza la memoria libre). También vale aclarar que este algoritmo
soporta inherentemente celdas de tamaño variable, por lo que los servicios
\code{alloc()} y \code{new()} \footnote{
Notar que \code{new()} es igual que en el marcado y barrido con
la salvedad de que en este caso toma como parámetro el tamaño de la celda.
} reciben como parámetro el tamaño de la
celda a asignar:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{if} \PYG{n}{free} \PYG{o}{+} \PYG{n}{size} \PYG{o}{\textgreater{}} \PYG{n}{fromspace} \PYG{o}{+} \PYG{n}{spacesize}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{k}{else}
      \PYG{n}{cell} \PYG{o}{=} \PYG{n}{free}
      \PYG{n}{free} \PYG{o}{=} \PYG{n}{free} \PYG{o}{+} \PYG{n}{size}
      \PYG{k}{return} \PYG{n}{cell}

\PYG{k}{function} \PYG{n}{new}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{cell} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{cell} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{cell} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{cell} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{throw} \PYG{n}{out\PYGZus{}of\PYGZus{}memory}
   \PYG{k}{return} \PYG{n}{cell}

\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{free} \PYG{o}{=} \PYG{n}{tospace}
   \PYG{k}{foreach} \PYG{n}{r} \PYG{k}{in} \PYG{n}{root\PYGZus{}set}
      \PYG{n}{r} \PYG{o}{=} \PYG{n}{copy}\PYG{p}{(}\PYG{n}{r}\PYG{p}{)}
   \PYG{n}{fromspace}\PYG{p}{,} \PYG{n}{tospace} \PYG{o}{=} \PYG{n}{tospace}\PYG{p}{,} \PYG{n}{fromspace}

\PYG{k}{function} \PYG{n}{copy}\PYG{p}{(}\PYG{n}{cell}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{if} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{forwarding\PYGZus{}address} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{cell}\PYG{p}{.}\PYG{n}{forwarding\PYGZus{}address} \PYG{o}{=} \PYG{n}{free}
      \PYG{n}{cell}\PYG{p}{.}\PYG{n}{copy\PYGZus{}to}\PYG{p}{(}\PYG{n}{free}\PYG{p}{)}
      \PYG{n}{free} \PYG{o}{=} \PYG{n}{free} \PYG{o}{+} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{size}
      \PYG{k}{foreach} \PYG{n}{child} \PYG{k}{in} \PYG{n}{cell}
         \PYG{n}{child} \PYG{o}{=} \PYG{n}{copy}\PYG{p}{(}\PYG{n}{child}\PYG{p}{)}
      \PYG{k}{return} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{forwarding\PYGZus{}address}
   \PYG{k}{else}
      \PYG{k}{return} \PYG{n}{cell}\PYG{p}{.}\PYG{n}{forwarding\PYGZus{}address}
\end{Verbatim}

Esta técnica tiene nombres variados en inglés: \emph{semi-space}, \emph{two-space}
o simplemente \emph{copying collector}. En este documento se denomina ``copia de
semi-espacio'' porque los otros nombres son demasiado generales y pueden
describir, por ejemplo, algoritmos donde no hay copia de celdas o donde no hay
2 semi-espacios (como se verá en \hyperlink{gc-art}{\emph{Estado del arte}}).

Al igual que el \hyperlink{gc-mark-sweep}{\emph{Marcado y barrido}} este algoritmo es \hyperlink{gc-direct}{\emph{indirecto}}, \hyperlink{gc-inc}{\emph{no incremental}} y \hyperlink{gc-concurrent}{\emph{stop-the-world}}. Las diferencias con los esquemas vistos hasta ahora son
evidentes. La principal ventaja sobre el marcado y barrido (que requiere una
pasada sobre el \emph{live set}, el marcado, y otra sobre el \emph{heap} entero, el
barrido) es que este método requiere una sola pasada y sobre las celdas vivas
del \emph{heap} solamente. La principal desventaja es copia memoria, lo que puede
ser particularmente costoso, además de requerir, como mínimo, el doble de
memoria de lo que el \emph{mutator} realmente necesita. Esto puede traer en
particular problemas con la memoria virtual y el caché, por la pobre localidad
de referencia.

Por lo tanto los recolectores de este tipo pueden ser convenientes por sobre
el marcado y barrido cuando se espera que el \emph{live set} sea muy pequeño luego
de una recolección. En estos casos el trabajo realizado por este tipo de
recolectores puede ser considerablemente menor que el del marcado y barrido.
Y por el contrario, si el \emph{working set} es pequeño, al ser \emph{compactado} en
memoria puede mejorar la localidad de referencia (si el \emph{working set} es
grande se corre el riesgo de que la localidad de referencia empeore al moverse
las celdas).


\subsubsection{Ejemplo}

A continuación se presenta un sencillo ejemplo del algoritmo. Se parte de una
estructura simple con 4 celdas en el \emph{Fromspace} (que incluye un pequeño ciclo
para mostrar que este algoritmo tampoco tiene inconvenientes para
recolectarlos). Asumimos que ya no queda lugar en el \emph{Fromspace} por lo que
comienza la ejecución de \code{collect()}. Se comienza por el \emph{root set} que
apunta a \code{h3}, por lo tanto ésta es movida al \emph{Tospace} primero, dejando una
\emph{forwarding address} a la nueva ubicación (ver figura
\vref{fig:gc-copy-ex-1}).
\begin{figure}[btp]
\centering
\subfloat[Estructura inicial del \emph{heap}. El \emph{Fromspace} está complete y se inicial
la recolección.]{
\includegraphics{aafig-e141b209f04d5a4fc642d60f33653df0a61b6b4e.pdf}
}
\hspace{0.1in}
\subfloat[Se sigue la referencia del \emph{root set}, copiando \code{h3} al \emph{Tospace}
y dejando una \emph{forwarding address}.]{
\includegraphics{aafig-3774acc76a8fa202f0475010f0acfa11c0608a9a.pdf}
}
\caption[Ejemplo de recolección con copia de semi-espacios (parte 1)]{Ejemplo de recolección con copia de semi-espacios (parte 1).}
\label{fig:gc-copy-ex-1}
\end{figure}


A continuación se copian las \emph{hijas} de \code{h3}, en este caso sólo \code{h2}, que
se ubica en el \emph{Tospace} a continuación de \code{h3}, dejando nuevamente su
\code{forwarding address} en la celda original. Al proceder recursivamente, se
procede a copiar \code{h1} al \emph{Tospace}, dejando una vez más la \emph{forwarding
address} en la celda original y procediendo con las hijas. Aquí podemos
observar que al seguirse la referencia $h1 \to h2$, como \code{h2} ya había
sido visitada, solamente se actualiza la referencia apuntando a la nueva
ubicación de \code{h2} pero no se vuelve a copiar la celda (ver figura
\vref{fig:gc-copy-ex-2}).
\begin{figure}[btp]
\centering
\subfloat[Se sigue $h3 \to h2$, copiando \code{h2} al \emph{Tospace} y dejando una
\emph{forwarding address}.]{
\includegraphics{aafig-e460b531d050b9c9aa8751addcb30fcf1e0d7242.pdf}
}
\hspace{0.1in}
\subfloat[Se sigue $h2 \to h1$, copiando \code{h1}. Luego $h1 \to h2$
pero \code{h2} no se copia, sólo se actualiza la referencia con la
\emph{forwarding address}.]{
\includegraphics{aafig-d4b475ca9de4009ba3d13f08a3136b522d4ee411.pdf}
}
\caption[Ejemplo de recolección con copia de semi-espacios (parte 2)]{Ejemplo de recolección con copia de semi-espacios (parte 2).}
\label{fig:gc-copy-ex-2}
\end{figure}


Se termina de copiar recursivamente las hijas de \code{h1} al copiar \code{h4} que
resulta la última celda (sin hijas). Finalmente se invierten los roles de los
semi-espacios y se actualiza la referencia del \emph{root set} para que apunte a la
nueva ubicación de \code{h3}, como se muestra en la figura
\vref{fig:gc-copy-ex-3}.
\begin{figure}[btp]
\centering
\subfloat[Se sigue $h1 \to h4$ copiando \emph{h4{}`} al \emph{Tospace} y dejando una
\emph{forwarding address}.]{
\includegraphics{aafig-f22eb3b1cb81197a15ae5cfe44ca1d4888b7840c.pdf}
}
\hspace{0.1in}
\subfloat[Se finaliza la recolección, se intercambian los roles de los
semi-espacios y se actualiza la referencia del \emph{root set}.]{
\includegraphics{aafig-7b1f454ea819e8c2ade031554858ee4a93cea6b1.pdf}
}
\caption[Ejemplo de recolección con copia de semi-espacios (parte 3)]{Ejemplo de recolección con copia de semi-espacios (parte 3).}
\label{fig:gc-copy-ex-3}
\end{figure}

\hypertarget{gc-art}{}

\section{Estado del arte}

La manera en que la investigación sobre recolección de basura ha crecido es
realmente sorprendente. Hay, al menos, 2995 publicaciones sobre recolección de
basura registradas al momento de escribir este documento \hyperlink{gcbib}{{[}GCBIB{]}}. Esto hace
que el análisis del estado del arte sea particularmente complejo y laborioso.

Analizar todas las publicaciones existentes es algo excede los objetivos de
este trabajo, por lo tanto se analizó solo una porción significativa,
utilizando como punto de partida a \hyperlink{joli96}{{[}JOLI96{]}}.

De este análisis se observó que la gran mayoría de los algoritmos son
combinaciones de diferentes características básicas; por lo tanto se intentó
aislar estas características que son utilizadas como bloques de construcción
para algoritmos complejos. Ésta tampoco resultó ser una tarea sencilla debido
a que muchos de estos bloques de construcción básicos están interrelacionados
y encontrar una división clara para obtener características realmente atómicas
no es trivial.

La construcción de recolectores más complejos se ve alimentada también por la
existencia de recolectores \emph{híbridos}; es decir, recolectores que utilizan más
de un algoritmo dependiendo de alguna característica de la memoria
a administrar. No es poco común observar recolectores que utilizan un
algoritmo diferente para celdas que sobreviven varias recolecciones que para
las que mueren rápidamente, o que usan diferentes algoritmos para objetos
pequeños y grandes, o que se comporten de forma conservativa para ciertas
celdas y sean precisos para otras.

De todas estas combinaciones resulta el escenario tan fértil para la
investigación sobre recolección de basura.

A continuación se presentan las principales clases de algoritmos
y características básicas encontradas durante la investigación del estado del
arte. La separación de clases y aislamiento de características no es siempre
trivial, ya que hay ciertas clases de recolectores que están interrelacionadas
(o ciertas características pueden estar presentes sólo en recolectores de una
clase en particular).


\hypertarget{gc-direct}{}\subsection{Recolección directa / indirecta}

Generalmente se llama recolección \textbf{directa} a aquella en la cual el
compilador o lenguaje instrumenta al \emph{mutator} de forma tal que la información
sobre el grafo 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 (ver \hyperlink{gc-rc}{\emph{Conteo de referencias}}). Esto permite reclamar una celda
instantáneamente cuando el \emph{mutator} deja de hacer referencia a ella.  Este
tipo de recolectores son inherentemente \hyperlink{gc-inc}{\emph{incrementales}}.

Por el contrario, los recolectores \textbf{indirectos} normalmente no interfieren
con el \emph{mutator} en cada actualización del grafo de conectividad (exceptuando
algunos \hyperlink{gc-inc}{\emph{recolectores incrementales}} que a veces necesitan
instrumentar el \emph{mutator} pero no para mantener el estado del grafo de
conectividad completo). La recolección se dispara usualmente cuando el
\emph{mutator} requiere asignar 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 \emph{basura}.
Prácticamente todos los recolectores menos el \hyperlink{gc-rc}{\emph{conteo de referencias}} están dentro de esta categoría (como por ejemplo, el \hyperlink{gc-mark-sweep}{\emph{marcado
y barrido}} y \hyperlink{gc-copy}{\emph{copia de semi-espacio}}).

Otros ejemplos de recolectores modernos \emph{directos} son el recolector de basura
de \href{http://www.python.org/}{Python} \hyperlink{nas00}{{[}NAS00{]}} y \hyperlink{lins05}{{[}LINS05{]}} (aunque ambos tiene un algoritmo \emph{indirecto}
para recuperar ciclos).
\hypertarget{gc-inc}{}

\subsection{Recolección incremental}

Recolección incremental es aquella que se realiza de forma intercalada con el
\emph{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
total de recolección en términos de tiempo).

De los algoritmos clásicos el único que es incremental en su forma más
básica es el \hyperlink{gc-rc}{\emph{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
\emph{mutator} asigna memoria. En general para hacer esto es también necesario
instrumentar al \emph{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 \emph{desactualizado} y así re-escanearlo nuevamente en
la próxima iteración. Para realizar esto en recolectores \hyperlink{gc-direct}{\emph{indirectos}} se utiliza la \hyperlink{gc-intro-tricolor}{\emph{abstracción tricolor}};
cuando el \emph{mutator} cambia una referencia, se marca \emph{gris} la celda que la
contiene, de modo que el recolector vuelva a visitarla.

En general el rendimiento de los recolectores incrementales disminuye
considerablemente cuando el \emph{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.

Ejemplos de recolectores que se encuentran dentro de esta categoría son
\hyperlink{boeh91}{{[}BOEH91{]}}, \hyperlink{lins05}{{[}LINS05{]}},
\hypertarget{gc-concurrent}{}

\subsection{Recolección concurrente / paralela / \emph{stop-the-world}}

Los recolectores concurrentes son aquellos que pueden correr en paralelo con
el \emph{mutator}. Por el contrario, aquellos que pausan el \emph{mutator} para realizar
la recolección son usualmente denominados \emph{stop-the-world} (\emph{detener el
mundo}), haciendo referencia a que pausan todos los hilos del \emph{mutator} para
poder escanear el grafo de conectividad de forma consistente. Hay una tercera
clase de colectores que si bien son \emph{stop-the-world}, utilizan todos los hilos
disponibles para realizar la recolección (ver figura
\vref{fig:gc-concurrent}).
\begin{figure}[btp]
\centering
\subfloat[\emph{Stop-the-world}.]{
\includegraphics{aafig-adbe0d02b05a2f83130290f96c93a91165864a95.pdf}
}
\hspace{0.1in}
\subfloat[Paralelo.]{
\includegraphics{aafig-63e5de268cca64ddd08523b05bbd6b10a7b4e100.pdf}
}
\hspace{0.1in}
\subfloat[Concurrente.]{
\includegraphics{aafig-19c82f75651a45781f31c2567f539c7bd1c10c7f.pdf}
}
\caption[Distintos tipos de recolectores según el comportamiento en ambientes
multi-hilo]{Distintos tipos de recolectores según el comportamiento en ambientes
multi-hilo.}
\label{fig:gc-concurrent}
\end{figure}


Para lograr que un recolector sea concurrente generalmente el mecanismo es
similar al necesario para hacer un \hyperlink{gc-inc}{\emph{recolector incremental}}: hay
que instrumentar al \emph{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, además de la sincronización necesaria entre \emph{mutator}
y recolector.

¿Cuál es la idea entonces de un recolector concurrente? Una vez más, al igual
que los recolectores incrementales, el principal objetivo es disminuir las
largas pausas provocadas por la recolección de basura. Sin embargo, este tipo
de algoritmos además permite hacer un mejor aprovechamiento de las
arquitecturas \emph{multi-core} \footnote{
Una arquitectura \emph{multi-core} es aquella que combina dos
o más núcleos (\emph{cores}) independientes que trabajan a la misma frecuencia,
pero dentro de un solo circuito integrado o procesador.
} que cada vez son más comunes, ya
que el \emph{mutator} y el recolector pueden estar corriendo realmente en paralelo,
cada uno en un procesador distinto. Algunos recolectores van más allá
y permiten incluso paralelizar la recolección de basura en varios hilos
(\hyperlink{huel98}{{[}HUEL98{]}}, \hyperlink{lins05}{{[}LINS05{]}}). Otros ejemplos de recolectores concurrentes (aunque no
ofrece paralelización del procesamiento del recolector en varios hilos) son
\hyperlink{boeh91}{{[}BOEH91{]}}, \hyperlink{rodr97}{{[}RODR97{]}}.

Todos los \hyperlink{gc-classic}{\emph{algoritmos clásicos}} que se han citado son del
tipo \emph{stop-the-world}.
\hypertarget{gc-free-list}{}

\subsection{Lista de libres / \emph{pointer bump allocation}}

Esta clasificación se refiere principalmente a la forma en que se organiza el
\emph{heap}, íntimamente relacionado al \emph{low level allocator}. Si bien se ha dicho
que en este trabajo no se prestará particular atención a este aspecto, en
ciertos algoritmos es tan relevante que tampoco es sensato pasarlo por alto
completamente.

En términos generales, hay dos formas fundamentales de organizar el \emph{heap},
manteniendo una lista de libres o realizando \emph{pointer bump allocation}, como
se explicó en \hyperlink{gc-copy}{\emph{Copia de semi-espacio}}. La primera forma consiste, a grandes rasgos, en
separar el \emph{heap} en celdas (que pueden agruparse según tamaño) y enlazarlas
en una lista de libres. Al solicitarse una nueva celda simplemente se la
desenlaza de la lista de libres. Por otro lado, cuando el recolector detecta
una celda \emph{muerta}, la vuelve a enlazar en la lista de libres. Este es un
esquema simple pero con limitaciones, entre las principales, el costo de
asignar puede ser alto si hay muchos tamaños distintos de celda y soportar
tamaño de celda variable puede ser complejo o acarrear muchas otras
ineficiencias. El \hyperlink{gc-mark-sweep}{\emph{marcado y barrido}} en general usa este
esquema, al igual que el \hyperlink{gc-rc}{\emph{conteo de referencias}}.

Otro forma de organizar el \emph{heap} es utilizándolo como una especie de \emph{stack}
en el cual para asignar simplemente se incrementa un puntero. Este esquema es
simple y eficiente, si el recolector puede mover celdas (ver
\hyperlink{gc-moving}{\emph{Movimiento de celdas}}); de otra manera asignar puede ser muy costoso si hay que
buscar un \emph{hueco} en el heap (es decir, deja de reducirse a incrementar un
puntero). El clásico ejemplo de esta familia es el algoritmo visto en
\hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

Sin embargo, entre estos dos extremos, hay todo tipo de híbridos. Existen
recolectores basados en \emph{regiones}, que se encuentran en un punto intermedio.
Dentro de una región se utiliza un esquema de \emph{pointer bump allocation} pero
las regiones en sí se administran como una lista de libres (como por ejemplo
\hyperlink{blac08}{{[}BLAC08{]}}). Otra variación (más común) de este esquema son los \emph{two level
allocators} que asignan páginas completas (similar a las regiones) y dentro de
cada página se asignan las celdas. Ambas, páginas y celdas, se administran
como listas de libres (ejemplos que utilizan este esquema son \hyperlink{boehwd}{{[}BOEHWD{]}} y el
\hyperlink{dgc-actual}{\emph{recolector actual de D}}).
\hypertarget{gc-moving}{}

\subsection{Movimiento de celdas}

Otra característica muy importante del recolector de basura es si mueve las
celdas o no. En general el movimiento de celdas viene de la mano del esquema
de \hyperlink{gc-free-list}{\emph{pointer bump allocation}}, ya que \emph{compacta} todas las
celdas \emph{vivas} al comienzo del \emph{heap} luego de una recolección, permitiendo
este esquema para asignar nuevas celdas, pero puede utilizarse en esquemas
híbridos como recolectores basados en \emph{regiones} (por ejemplo \hyperlink{blac08}{{[}BLAC08{]}}).

Además los recolectores con movimiento de celdas deben ser \hyperlink{gc-conserv}{\emph{precisos}}, porque es necesario tener la información completa de los tipos
para saber cuando actualizar los punteros (de otra manera se podría escribir
un dato de una celda que no era un puntero). Para que un recolector pueda
mover celdas, aunque sea parcialmente, en recolectores \emph{semi-precisos} se
utiliza un método conocido como \emph{pinning} (que significa algo como \emph{pinchar
con un alfiler}); una celda es \emph{pinned} (\emph{pinchada}) cuando hay alguna
referencia no-precisa a ella, y por lo tanto no puede ser movida (porque no se
puede estar seguro si es posible actualizar dicha referencia).

La ventaja principal de los colectores con movimiento es la posibilidad de
utilizar \hyperlink{gc-free-list}{\emph{pointer bump allocation}} y que es sencillo
implementar recolectores \hyperlink{gc-part}{\emph{generacionales}} sobre estos.

De los algoritmos clásicos sólo la \hyperlink{gc-copy}{\emph{copia de semi-espacios}}
mueve celdas, el \hyperlink{gc-rc}{\emph{conteo de referencias}} y \hyperlink{gc-mark-sweep}{\emph{marcado
y barrido}} no lo hacen. Además hay otro algoritmo bastante
básico que mueve celdas, el \textbf{marcado y compactado}. Éste no tiene
2 semi-espacios, directamente mueve las celdas compactándolas al comienzo del
\emph{heap}. El algoritmo es un poco más complejo que la \hyperlink{gc-copy}{\emph{copia de
semi-espacios}} pero suele proveer una mayor localidad de referencia
y no \emph{desperdicia} un semi-espacio que está inutilizado salvo en el momento de
la recolección. Por ejemplo para \href{http://www.mono-project.com/}{Mono}, que antes usaba un recolector
conservativo sin movimiento (\hyperlink{boehwd}{{[}BOEHWD{]}}) se está implementando un recolector de
este tipo \hyperlink{molawe}{{[}MOLAWE{]}} \hyperlink{mola06}{{[}MOLA06{]}}.
\hypertarget{gc-conserv}{}

\subsection{Recolectores conservativos versus precisos}

Los recolectores \emph{conservativos} son aquellos que tienen la capacidad de poder
lidiar con un \emph{root set} o celdas que no tengan información de tipos asociada.
Esto significa que el recolector no sabe donde hay punteros (o referencias) en
una celda o raiz dada. Es decir, una ubicación particular puede ser un puntero
o no. Esto trae una variada cantidad de problemas, como retención de celdas
que en realidad son \emph{basura} simplemente porque hay algún dato que coincide
con la dirección de memoria en la que está almacenada esa celda \emph{basura}
\footnote{
Esto es lo que se conoce como un \emph{falso positivo}, algo que
aparenta ser un puntero pero en realidad no lo es.
}. Además los recolectores puramente conservativos no puede mover
celdas (ver \hyperlink{gc-moving}{\emph{Movimiento de celdas}}), dado que no pueden actualizar los supuestos
punteros por la posibilidad de que sean \emph{falsos positivos}.

Sin embargo hay ciertas circunstancias que hacen que no quede más remedio que
el recolector sea conservativo, por ejemplo cuando se utiliza un recolector de
basura para un lenguaje que no ha sido pensado para tener uno (como C o C++).

Por el contrario, los recolectores que poseen a su disposición información
completa sobre el tipo de la celda, y por ende información sobre cuales de sus
campos son realmente punteros, son denominados \emph{precisos}. Estos recolectores
no están sujetos a estas limitaciones y por lo tanto son potencialmente más
eficientes en cuanto a tiempo y espacio. Los lenguajes que fueron diseñados
para tener un recolector de basura (y en especial aquellos que son de relativo
alto nivel) en general disponen de recolectores precisos.

Hay casos donde se posee información de tipos para algunas celdas solamente,
o más comúnmente se posee información de tipos de celdas que se encuentran en
el \emph{heap} pero no para el \emph{stack} y registros (por ejemplo \hyperlink{mola06}{{[}MOLA06{]}}). En
estos casos se puede adoptar un esquema híbrido y tratar algunas referencias
de forma conservativa y otras de forma precisa, de manera de mitigar, aunque
sea de forma parcial, los efectos adversos de los recolectores conservativos.
Estos recolectores son conocidos como \emph{semi-precisos}. Los recolectores
semi-precisos pueden mover celdas si utilizan un mecanismo de \emph{pinning} (ver
\hyperlink{gc-moving}{\emph{Movimiento de celdas}}).

El ejemplo de recolector conservativo por excelencia es el recolector
\href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/}{Boehm-Demers-Wiser} (\hyperlink{boeh88}{{[}BOEH88{]}}, \hyperlink{boeh91}{{[}BOEH91{]}}, \hyperlink{boeh93}{{[}BOEH93{]}}, \hyperlink{boehwd}{{[}BOEHWD{]}}) aunque
puede comportarse de forma semi-precisa si el usuario se encarga de darle la
información de tipos (en cuyo caso el recolector deja de ser transparente para
el usuario). Otros ejemplos de recolectores con cierto grado de precisión son
el \hyperlink{dgc-actual}{\emph{recolector actual de D}} y \hyperlink{blac08}{{[}BLAC08{]}}.
\hypertarget{gc-part}{}

\subsection{Recolección por particiones / generacional}

Otra forma de reducir la cantidad de pausas y la cantidad de trabajo realizado
por el recolector en general es dividiendo el \emph{heap} en particiones de manera
tal de recolectar solo las partes donde más probabilidad de encontrar \emph{basura}
haya.

Entonces, si el recolector tiene algún mecanismo para identificar zonas de
alta concentración de \emph{basura} puede hacer la recolección solo en ese área
donde el trabajo va a ser mejor recompensado (ver figura \vref{fig:gc-part}).
\begin{figure}[btp]
\centering

\includegraphics{aafig-8c53d6c24ac6c122a545112f8fc5b9c9f664af32.pdf}
\caption[Concentración de basura en distintas particiones del \emph{heap}]{Concentración de basura en distintas particiones del \emph{heap}.}
\label{fig:gc-part}
\end{figure}


Sin embargo encontrar zonas de alta concentración no es trivial. La forma más
divulgada de encontrar estas zonas es dividiendo el \emph{heap} en una partición
utilizada para almacenar celdas \emph{jóvenes} y otra para celdas \emph{viejas}. Una
celda \emph{vieja} es aquella que ha \emph{sobrevivido} una cantidad \emph{N} de
recolecciones, mientras que el resto se consideran \emph{jóvenes} (las celdas
\emph{nacen} jóvenes).  Los recolectores que utilizan este tipo de partición son
ampliamente conocido como recolectores \textbf{generacionales}. La \emph{hipótesis
generacional} dice que el área de celdas jóvenes tiene una mayor probabilidad
de ser un área de alta concentración de basura \hyperlink{joli96}{{[}JOLI96{]}}. Basándose en esto,
los recolectores generacionales primero intentan recuperar espacio del área de
celdas jóvenes y luego, de ser necesario, del área de celdas viejas. Es
posible tener varias generaciones e ir subiendo de generación a generación
a medida que es necesario. Sin embargo en general no se obtienen buenos
resultados una vez que se superan las 3 particiones. La complejidad que trae
este método es que para recolectar la generación joven es necesario tomar las
referencias de la generación vieja a la joven como parte del \emph{root set} (de
otra forma podrían tomarse celdas como \emph{basura} que todavía son utilizadas por
las celdas viejas). Revisar toda la generación vieja no es una opción porque
sería prácticamente lo mismo que realizar una recolección del \emph{heap} completo.
La solución está entonces, una vez más, en instrumentar el \emph{mutator} para que
avise al recolector cuando cambia una referencia de la generación vieja a la
joven (no es necesario vigilar las referencias en sentido inverso ya que
cuando se recolecta la generación vieja se hace una recolección del \emph{heap}
completo).

Sin embargo, a pesar de ser este el esquema más difundido para dividir el
\emph{heap} y realizar una recolección parcial sobre un área de alta concentración
de basura, no es la única. Otros recolectores proponen hacer un análisis
estático del código revisando la conectividad entre los objetos según sus
tipos (esto es posible solo en lenguajes con \emph{tipado} estático), de manera tal
de separar en distintas áreas grupos de tipos que no pueden tener referencias
entre sí \hyperlink{hirz03}{{[}HIRZ03{]}}. Este análisis hace que sea innecesario instrumentar el
\emph{mutator} para reportar al recolector cambios de referencias
inter-particiones, sencillamente porque queda demostrado que no existe dicho
tipo de referencias. Esto quita una de las principales ineficiencias
y complejidades del esquema generacional.

\resetcurrentobjects
\hypertarget{--doc-dgc}{}

\hypertarget{dgc}{}\chapter{Recolección de basura en D}

\href{http://www.digitalmars.com/d/}{D} propone un nuevo desafío en cuanto al diseño de un recolector de basura,
debido a la gran cantidad de características que tiene y paradigmas que
soporta.

\href{http://www.digitalmars.com/d/}{D} ya cuenta con un recolector que hace lo necesario para funcionar de forma
aceptable, pero su diseño e implementación son relativamente sencillos
comparados con el \hyperlink{gc-art}{\emph{estado del arte}} de la recolección de basura
en general. Además la implementación actual presenta una serie de problemas
que se evidencia en las quejas que regularmente la comunidad de usuarios de \href{http://www.digitalmars.com/d/}{D}
menciona en el grupo de noticias.

En esta sección se analizarán las necesidades particulares de \href{http://www.digitalmars.com/d/}{D} con respecto
a la recolección de basura. También se analiza el diseño e implementación del
recolector actual, presentando sus fortalezas y debilidades. Finalmente se
analiza la viabilidad de los diferentes algoritmos vistos en \hyperlink{gc-art}{\emph{Estado del arte}}.


\hypertarget{dgc-needs}{}\section{Características y necesidades particulares de D}

En esta sección se hará un recorrido por las características y necesidades
particulares que tiene \href{http://www.digitalmars.com/d/}{D} como lenguaje con respecto a la recolección de
basura.


\hypertarget{dgc-prob-low-level}{}\subsection{Programación de bajo nivel (\emph{system programming})}

Sin dudas las características de \href{http://www.digitalmars.com/d/}{D} que lo hacen más complejo a la hora de
implementar un recolector de basura son sus capacidades de programación de
bajo nivel (ver \hyperlink{d-low-level}{\emph{Programación de bajo nivel (system programming)}}).

Al proveer acceso a \emph{assembly}, permitir estructuras de tipo \emph{union} y ser
compatible con C/C++, el recolector de basura tiene muchas restricciones. Por
ejemplo debe tratar de forma conservativa los registros y el \emph{stack}, ya que
es la única forma de interactuar de forma segura con C/C++ y \emph{assembly}.

Además debe poder interactuar con manejo de memoria explícito, ya sea
omitiendo por completo el \emph{heap} del recolector o liberando explícitamente
memoria de éste. Esta característica es muy inusual en un recolector,
a excepción de recolectores conservativos diseñados para C/C++ que tienen las
mismas (o más) limitaciones.

La posibilidad de controlar la alineación de memoria es otra complicación
sobre el recolector de basura, incluso aunque éste sea conservativo. Dado que
tratar la memoria de forma conservativa byte a byte sería impracticable (tanto
por la cantidad de \emph{falsos positivos} que esto provocaría como por el impacto
en el rendimiento por el exceso de posibles punteros a revisar, además de lo
ineficiente que es operar sobre memoria no alineada), en general el recolector
asume que el usuario nunca va a tener la única referencia a un objeto en una
estructura no alineada al tamaño de palabra.
\hypertarget{d-prob-high-level}{}

\subsection{Programación de alto nivel}

Las características de programación de alto nivel también impone dificultades
o restricciones al recolector de basura (ver \hyperlink{d-high-level}{\emph{Programación de alto nivel}}). Por ejemplo
el soporte de rebanado (\emph{slicing}) de arreglos hace que el recolector deba
soportar punteros \emph{interiores} \footnote{
Los punteros \emph{interiores} son aquellos que en vez de apuntar
al inicio de una celda, apuntan a una dirección arbitraria dentro de ella.
Esto no es posible en muchos lenguajes de programación, como por ejemplo
\href{http://www.java.com/}{Java}, lo que simplifica la recolección de basura.
} (esto también es necesario
porque en general en \href{http://www.digitalmars.com/d/}{D} o en cualquier lenguaje de bajo nivel se puede tener
un puntero a cualquier parte de una celda).

Los arreglos dinámicos y asociativos en particular dependen fuertemente del
recolector de basura, en particular cuando se agregan elementos (o se
concatenan dos arreglos).

Dado que los \emph{strings} son arreglos dinámicos y que el lenguaje provee un buen
soporte de arreglos dinámicos y asociativos y \emph{slicing}, es de esperarse que
el recolector deba comportarse de forma correcta y eficiente ante las
operaciones más típicas de estas estructuras que dependan de él.
\hypertarget{dgc-prob-types}{}

\subsection{Información de tipos}

Hasta aquí \href{http://www.digitalmars.com/d/}{D} comparte todas las restricciones con respecto a la recolección
de basura con los lenguajes de bajo nivel que no tienen ningún soporte para
recolectar basura. Sin embargo, a diferencia de éstos, \href{http://www.digitalmars.com/d/}{D} tiene una
información de tipos más rica. Al momento de asignar memoria \href{http://www.digitalmars.com/d/}{D} puede proveer
cierta información sobre el objeto a asignar (como si puede contener punteros
o no) que puede ser utilizada por el recolector para realizar una recolección
más precisa (ver \hyperlink{gc-conserv}{\emph{Recolectores conservativos versus precisos}}).

En general esta información no es suficiente como para implementar un
recolector completamente preciso (no al menos sin agregar un mejor soporte de
reflexión al lenguaje) pero puede ser de ayuda considerable para el
recolector.
\hypertarget{dgc-prob-final}{}

\subsection{Orientación a objetos y finalización}

\href{http://www.digitalmars.com/d/}{D} soporta el paradigma de orientación a objetos, donde es común permitir que
un objeto, al ser destruido, realice alguna tarea de finalización (a través de
una función miembro llamada \emph{destructor}, o \code{\textasciitilde{}this()} en \href{http://www.digitalmars.com/d/}{D}). Esto significa
que el recolector, al encontrar que no hay más referencias a un objeto, debe
ejecutar el destructor.

La especificación dice \hyperlink{dwde}{{[}DWDE{]}}:
\begin{quote}

The garbage collector is not guaranteed to run the destructor for all
unreferenced objects. Furthermore, the order in which the garbage collector
calls destructors for unreference objects is not specified. This means that
when the garbage collector calls a destructor for an object of a class that
has members that are references to garbage collected objects, those
references may no longer be valid. This means that destructors cannot
reference sub objects.
\end{quote}

Afortunadamente el orden de finalización no está definido, ya que esto sería
extremadamente difícil de proveer por un recolector (si no imposible). Esto
significa que si bien se ejecutan los destructores de los objetos que dejan de
ser alcanzables desde el \emph{root set}, no se define en que orden se hace, y por
lo tanto un objeto no puede acceder a sus atributos que sean referencias
a otros objetos en un destructor.

Esta restricción en realidad se ve relaja con el soporte de \emph{RAII}. Si se
utiliza la palabra clave \code{scope} al crear una serie de objetos, estos serán
destruidos determinísticamente al finalizar el \emph{scope} actual en el orden
inverso al que fueron creados y, por lo tanto, un usuario podría hacer uso de
los atributos que sean referencias a otros objetos creados con \code{scope} si el
orden en que fueron creados (y por lo tanto en que serán destruidos) se lo
permite.

Sin embargo no hay forma actualmente de saber dentro de un destructor si éste
fue llamado determinísticamente o no, por lo tanto es virtualmente imposible
hacer uso de esta distinción, a menos que una clase sea declarada para ser
creada solamente utilizando la palabra reservada \code{scope}.

Cabe aclarar que, estrictamente hablando y según la especificación de \href{http://www.digitalmars.com/d/}{D}, el
recolector no debe garantizar la finalización de objetos bajo ninguna
circunstancia, es decir, el recolector podría no llamar a ningún destructor.
Sin embargo esto es probablemente una vaguedad en la redacción y dadas las
garantías que provee la implementación actual la comunidad de \href{http://www.digitalmars.com/d/}{D} cuenta con
ellas.
\hypertarget{dgc-actual}{}

\section{Recolector de basura actual de D}

Como paso básico fundamental para poder mejorar el recolector de basura de \href{http://www.digitalmars.com/d/}{D},
primero hay que entender la implementación actual, de forma de conocer sus
puntos fuertes, problemas y limitaciones.

Como se mencionó en la sección \hyperlink{d-lang}{\emph{El lenguaje de programación D}}, hay dos bibliotecas base para
soportar el lenguaje (\emph{runtimes}): \href{http://www.dsource.org/projects/phobos}{Phobos} y \href{http://www.dsource.org/projects/tango}{Tango}. La primera es la
biblioteca estándar de \href{http://www.digitalmars.com/d/}{D}, la segunda un proyecto más abierto y dinámico que
surgió como alternativa a \href{http://www.dsource.org/projects/phobos}{Phobos} dado que estaba muy descuidada y que era muy
difícil impulsar cambios en ella. Ahora \href{http://www.dsource.org/projects/phobos}{Phobos} tiene el agravante de estar
\emph{congelada} en su versión 1 (solo se realizan correcciones de errores).

Dado que \href{http://www.dsource.org/projects/tango}{Tango} está mejor organizada, su desarrollo es más abierto (aceptan
cambios y mejoras) y que hay una mayor disponibilidad de programas
y bibliotecas escritos para \href{http://www.dsource.org/projects/tango}{Tango}, en este trabajo se decide tomar esta
biblioteca \emph{runtime} como base para el análisis y mejoras propuestas, a pesar
de ser \href{http://www.dsource.org/projects/phobos}{Phobos} la estándar. De todas formas el recolector de basura de \href{http://www.dsource.org/projects/tango}{Tango}
es prácticamente el mismo que el de \href{http://www.dsource.org/projects/phobos}{Phobos}, por lo tanto éste análisis en
particular es válido para cualquiera de las dos.

El recolector actual es un recolector \hyperlink{gc-direct}{\emph{indirecto}}, \hyperlink{gc-inc}{\emph{no
incremental}} que realiza un \hyperlink{gc-mark-sweep}{\emph{marcado y barrido}}
relativamente básico.  A diferencia del algoritmo clásico presentado éste
realiza un marcado no recursivo. La fase de marcado es \hyperlink{gc-concurrent}{\emph{stop-the-world
}} mientras que la fase de barrido corre en paralelo con el
\emph{mutator}, excepto el hilo que disparó la recolección que es quien efectúa el
barrido (además los hilos que intenten asignar nueva memoria o interactuar con
el recolector de cualquier otra forma se bloquean hasta que la fase de barrido
concluya). El marcado es casi totalmente \hyperlink{gc-conserv}{\emph{conservativo}}; si
bien posee alguna información de tipos (distingue entre celdas que pueden
tener punteros y celdas que definitivamente no los tienen, pero no dispone de
información sobre qué campos de las celdas son punteros y cuales no). Además
no tiene soporte alguno de \hyperlink{gc-part}{\emph{recolección particionada}}.

Si bien el recolector es bastante básico, posee una \hyperlink{dgc-org}{\emph{organización de
memoria}} relativamente moderna (utiliza una \hyperlink{gc-free-list}{\emph{lista de libres}} con un \emph{two level allocator}) y algunas optimizaciones
particulares para amortiguar casos patológicos.


\hypertarget{dgc-org}{}\subsection{Organización del \emph{heap}}

La memoria del \emph{heap} está organizada en \emph{pools}. Un \emph{pool} es una región de
\emph{páginas} contiguas. Una página es, en general, la unidad mínima de memoria que
maneja un sistema operativo con soporte de memoria virtual. Cada página dentro
de un \emph{pool} sirve a su vez como contenedora de bloques (llamados \emph{bin} en la
\hyperlink{dgc-impl}{\emph{implementación}}) de tamaño fijo. Todos los bloques
pertenecientes a la misma página tienen el mismo tamaño de bloque (ver figura
\vref{fig:dgc-org}). Los tamaños de bloque posibles son potencias de 2 desde
16 bytes hasta 4096 (el tamaño típico de una página), es decir: 16, 32, 64,
128, 256, 512, 1024, 2048 y 4096 \footnote{
Además existe otro tamaño de bloque especial que se utiliza
para indicar la continuación de un objeto grande (que ocupan más de una
página).
}. Todos los objetos, arreglos
o celdas en general se ubican en estos bloques (en uno del tamaño más pequeño
que haya que sea suficientemente grande como para almacenar dicho objeto).  En
caso de que un objeto sea mayor a una página, se utilizan la menor cantidad de
páginas contiguas de un pool que tengan espacio suficiente para almacenar
dicho objeto.
\begin{figure}[btp]
\centering

\includegraphics{aafig-b3935984a899b7594d330c9a5590d4403fb2a51c.pdf}
\caption[Organización del \emph{heap} del recolector de basura actual de D]{Organización del \emph{heap}. En este ejemplo todos los \emph{pools} tienen 2 páginas
excepto el \emph{pool} 2 que tiene una sola.  El tamaño de bloque que almacena
cada página varía entre 64 bytes (página 0 del \emph{pool} 2) hasta 4096 (ambas
páginas del \emph{pool} N) que es una página completa.}
\label{fig:dgc-org}
\end{figure}


Cada página de un \emph{pool} puede tener asignado un tamaño de bloque específico
o puede estar libre. A su vez, cada bloque puede estar ocupado por una celda
o estar libre. Los bloques libres de un tamaño específico (a excepción de
aquellos bloques que ocupen una página entera) además forman parte de una
\hyperlink{gc-free-list}{\emph{lista de libres}} (ver figura \vref{fig:dgc-free-list}).
Esto permite asignar objetos relativamente pequeños de forma bastante
eficiente.
\begin{figure}[btp]
\centering
\includegraphics{graphviz-a441958ad4aff5349f84be2b7926c115d1e76f0c.pdf}\caption[Ejemplo de listas de libres]{Ejemplo de listas de libres.}
\label{fig:dgc-free-list}
\end{figure}



\subsubsection{Atributos de \emph{pool}}

Cada \emph{pool} tiene la siguiente información asociada:
\begin{description}
\item[{\emph{number\_of\_pages}}] \leavevmode\\
Cantidad de páginas que tiene. Esta cantidad es fija en toda la vida de un
\emph{pool}.

\item[{\emph{pages}}] \leavevmode\\
Bloque de memoria contiguo de tamaño \code{PAGE\_SIZE * number\_of\_pages}
(siendo \code{PAGE\_SIZE} el tamaño de página, que normalmente son 4096 bytes).

\end{description}


\subsubsection{Atributos de página}

Cada página dentro de un \emph{pool} tiene un único atributo asociado: \emph{block\_size}.
Se trata del tamaño de los bloques que almacena esta página.

Una página siempre almacena bloques del mismo tamaño, que pueden ser 16, 32,
64, 128, 256, 512, 1024, 2048 o 4096 (llamado con el nombre especial
\code{PAGE}). Además hay dos tamaños de bloque simbólicos que tienen un
significado especial:
\begin{description}
\item[{\code{FREE}}] \leavevmode\\
Indica que la página está completamente libre y disponible para albergar
cualquier tamaño de bloque que sea necesario (pero una vez que se le asignó
un nuevo tamaño de bloque ya no puede ser cambiado hasta que la página
vuelva a liberarse por completo).

\item[{\code{CONTINUATION}}] \leavevmode\\
Indica que esta página es la continuación de un objeto grande (es decir,
que ocupa dos o más páginas). Luego se presentan más detalles sobre objetos
grandes.

\end{description}

Las páginas con estos tamaños de bloque especiales conceptualmente no
contienen bloques.


\subsubsection{Atributos de bloque}

Cada bloque tiene asociados varios atributos:
\begin{description}
\item[{\emph{mark}}] \leavevmode\\
Utilizado en la fase de \hyperlink{dgc-algo-mark}{\emph{marcado}}, indica que un nodo
ya fue visitado (serían las celdas \emph{negras} en la \hyperlink{gc-intro-tricolor}{\emph{abstracción
tricolor}}).

\item[{\emph{scan}}] \leavevmode\\
Utilizado también en la fase de \hyperlink{dgc-algo-mark}{\emph{marcado}}, indica que
una celda visitada todavía tiene \emph{hijas} sin marcar (serían las celdas
\emph{grises} en la \hyperlink{gc-intro-tricolor}{\emph{abstracción tricolor}}).

\item[{\emph{free}}] \leavevmode\\
Indica que el bloque está libre (no está siendo utilizado por ningún objeto
\emph{vivo}). Esto es necesario solo por la forma en la que realiza el
\hyperlink{dgc-algo-mark}{\emph{marcado}} y \hyperlink{dgc-algo-sweep}{\emph{barrido}} en el
\hyperlink{dgc-algo}{\emph{algoritmo actual}} (las celdas con este atributo son
tomadas como \emph{basura} aunque estén marcadas con \emph{mark}).

\item[{\emph{final}}] \leavevmode\\
Indica que el bloque contiene un objeto que tiene un destructor (que debe
ser llamado cuando la celda pasa de \emph{viva} a \emph{basura}).

\item[{\emph{noscan}}] \leavevmode\\
Indica que el bloque contiene un objeto que no tiene punteros y por lo
tanto no debe ser escaneado (no tiene \emph{hijas}).

\end{description}


\subsubsection{Objetos grandes}

El recolector de basura actual de \href{http://www.digitalmars.com/d/}{D} trata de forma diferente a los objetos
grandes. Todo objeto grande empieza en un bloque con tamaño \code{PAGE}
y (opcionalmente) continúa en los bloques contiguos subsiguientes que tengan
el tamaño de bloque \code{CONTINUATION} (si el objeto ocupa más que una página).
El fin de un objeto grande queda marcado por el fin del \emph{pool} o una página
con tamaño de bloque distinto a \code{CONTINUATION} (lo que suceda primero).

Cuando un objeto grande se convierte en \emph{basura}, todas sus páginas se liberan
por completo, siendo marcadas con tamaño \code{FREE} para que puedan ser
almacenado en ellas otros objetos grandes o incluso nuevos bloques de un
tamaño determinado.
\hypertarget{dgc-algo}{}

\subsection{Algoritmos del recolector}

A continuación se explica como provee el recolector actual de \href{http://www.digitalmars.com/d/}{D} los servicios
básicos que debe proveer cualquier recolector, como se presentó en la sección
\hyperlink{gc-intro-services}{\emph{Servicios}}.

Cabe aclarar que se presenta una versión simplificada del algoritmo, o más
precisamente, de la implementación del algoritmo, ya que no se exponen en esta
sección muchas optimizaciones que harían muy compleja la tarea de explicar
como funciona conceptualmente. En la siguiente sección, \hyperlink{dgc-impl}{\emph{Detalles de implementación}}, se
darán más detalles sobre las optimizaciones importantes y diferencias con el
algoritmo aquí presentado, junto con detalles sobre como se implementa la
organización del \emph{heap} que se explicó en la sección anterior.


\hypertarget{dgc-algo-collect}{}\subsubsection{Recolección}

A grandes rasgos el algoritmo de recolección puede resumirse de las dos fases
básicas de cualquier algoritmo de \hyperlink{gc-mark-sweep}{\emph{marcado y barrido}}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{sweep\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
\end{Verbatim}
\hypertarget{dgc-algo-mark}{}

\subsubsection{Fase de marcado}

Esta fase consiste de varios pasos, que pueden describirse con el siguiente
algoritmo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{false}
   \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{clear\PYGZus{}mark\PYGZus{}scan\PYGZus{}bits}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}free\PYGZus{}lists}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}static\PYGZus{}data}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{push\PYGZus{}registers\PYGZus{}into\PYGZus{}stack}\PYG{p}{(}\PYG{n+nb}{thread\PYGZus{}self}\PYG{p}{)}
   \PYG{n+nb}{thread\PYGZus{}self}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end} \PYG{o}{=} \PYG{n+nb}{get\PYGZus{}stack\PYGZus{}top}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}stacks}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{pop\PYGZus{}registers\PYGZus{}from\PYGZus{}stack}\PYG{p}{(}\PYG{n+nb}{thread\PYGZus{}self}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}user\PYGZus{}roots}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}heap}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
\end{Verbatim}

La variable \textbf{global} \code{more\_to\_scan} indica al algoritmo iterativo cuando
debe finalizar: la función \code{mark\_range()} (que veremos más adelante) lo pone
en \code{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 \code{stop\_the\_world()} y \code{start\_the\_world()} pausan y reanudan
todos los hilos respectivamente (salvo el actual). Al pausar los hilos además
se apilan los registros del procesador en el \emph{stack} y se guarda la posición
actual del \emph{stack} para que la fase de marcado pueda recorrerlos \footnote{
El procedimiento para apilar y desapilar los registros en el
\emph{stack} se realiza en realidad utilizando las señales \code{SIGUSR1}
y \code{SIGUSR2} (respectivamente). Es el manejador de la señal el que en
realidad apila y desapila los registros y guarda el puntero al \emph{stack}. Se
omiten los detalles para simplificar la explicación del algoritmo.
}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{thread} \PYG{k}{in} \PYG{n}{threads}
      \PYG{k}{if} \PYG{n}{thread} \PYG{k}{is} \PYG{n+nb}{thread\PYGZus{}self}
         \PYG{k}{continue}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n+nb}{pause}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{push\PYGZus{}registers\PYGZus{}into\PYGZus{}stack}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{)}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end} \PYG{o}{=} \PYG{n+nb}{get\PYGZus{}stack\PYGZus{}top}\PYG{p}{(}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{thread} \PYG{k}{in} \PYG{n}{reversed}\PYG{p}{(}\PYG{n}{threads}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{thread} \PYG{k}{is} \PYG{n+nb}{thread\PYGZus{}self}
         \PYG{k}{continue}
      \PYG{n}{pop\PYGZus{}registers\PYGZus{}from\PYGZus{}stack}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{)}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n+nb}{resume}\PYG{p}{(}\PYG{p}{)}
\end{Verbatim}

La función \code{clear\_mark\_scan\_bits()} se encarga de restablecer todos los
atributos \emph{mark} y \emph{scan} de cada bloque del \emph{heap}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{clear\PYGZus{}mark\PYGZus{}scan\PYGZus{}bits}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{false}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{false}
\end{Verbatim}

La función \code{mark\_free\_lists()} por su parte se encarga de activar el bit
\emph{mark} de todos los bloques de las listas de libres de manera de que la fase
de marcado (que es iterativa y realiza varias pasadas sobre \textbf{todo} el
\emph{heap}, incluyendo las celdas libres) no visite las celdas libres perdiendo
tiempo sin sentido y potencialmente manteniendo \emph{vivas} celdas que en
realidad son \emph{basura} (\emph{falsos positivos}):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}free\PYGZus{}lists}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{free\PYGZus{}list} \PYG{k}{in} \PYG{n}{free\PYGZus{}lists}
      \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{free\PYGZus{}list}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{true}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}
\end{Verbatim}

Notar que los bloques libres quedan entonces marcados aunque sean \emph{basura} por
definición. Para evitar que en la etapa de barrido se tomen estos bloques como
celdas vivas, a todos los bloques en la lista de libres también se los marca
con el bit \emph{free}, así el barrido puede tomar como \emph{basura} estos bloques
aunque estén marcados.

El \emph{root set} está compuesto por el área de memoria estática (variables
globales), los \emph{stacks} de todos los hilos y los registros del procesador.
Primero se marca el área de memoria estática de manera \hyperlink{gc-conserv}{\emph{conservativa}} (es decir, tomando cada \emph{word} como si fuera un puntero):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}static\PYGZus{}data}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{static\PYGZus{}data}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{static\PYGZus{}data}\PYG{p}{.}\PYG{n}{end}\PYG{p}{)}
\end{Verbatim}

Para poder tomar los registros como parte del \emph{root set} primero se apilan
en el \emph{stack} a través de la función:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{push\PYGZus{}registers\PYGZus{}into\PYGZus{}stack}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{register} \PYG{k}{in} \PYG{n}{thread}\PYG{p}{.}\PYG{n}{registers}
      \PYG{n}{push}\PYG{p}{(}\PYG{n}{register}\PYG{p}{)}
\end{Verbatim}

Y luego, al reiniciar los hilos cuando se termina de marcar, se descartan
sacándolos de la pila (no es necesario ni correcto restablecer los valores ya
que podrían tener nuevos valores):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{pop\PYGZus{}registers\PYGZus{}from\PYGZus{}stack}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{register} \PYG{k}{in} \PYG{n}{reverse}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{.}\PYG{n}{registers}\PYG{p}{)}
      \PYG{n}{pop}\PYG{p}{(}\PYG{p}{)}
\end{Verbatim}

Una vez hecho esto, basta marcar (de forma conservativa) los \emph{stacks} de todos
los threads para terminar de marcar el \emph{root set}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}stacks}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{thread} \PYG{k}{in} \PYG{n}{threads}
      \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{thread}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end}\PYG{p}{)}
\end{Verbatim}

Dado que \href{http://www.digitalmars.com/d/}{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 \emph{root
set} convencional ni en el \emph{heap} del recolector. Para evitar que se libere
alguna celda a la cual todavía existen referencias desde memoria administrada
por el usuario, éste debe informarle al recolector sobre la existencia de
estas nuevas raíces. Es por esto que para concluir el marcado del \emph{root set}
completo se procede a marcar las raíces definidas por el usuario:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}user\PYGZus{}roots}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{root\PYGZus{}range} \PYG{k}{in} \PYG{n}{user\PYGZus{}roots}
      \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{root\PYGZus{}range}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{root\PYGZus{}range}\PYG{p}{.}\PYG{n}{end}\PYG{p}{)}
\end{Verbatim}

El algoritmo de marcado no es recursivo sino iterativo por lo tanto al marcar
una celda (o bloque) no se siguen sus \emph{hijas}, solo se activa el bit de \emph{scan}
(a menos que la celda no contenga punteros, es decir, tenga el bit \emph{noscan}):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{end}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pointer} \PYG{o}{=} \PYG{n}{begin}
   \PYG{k}{while} \PYG{n}{pointer} \PYG{o}{\textless{}} \PYG{n}{end}
      \PYG{p}{[}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{,} \PYG{n}{block}\PYG{p}{]} \PYG{o}{=} \PYG{n}{find\PYGZus{}block}\PYG{p}{(}\PYG{n}{pointer}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{k}{not} \PYG{n+nb}{null} \PYG{k}{and} \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{k}{is} \PYG{n+nb}{false}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{true}
         \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{k}{is} \PYG{n+nb}{false}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{true}
            \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{true}
      \PYG{n}{pointer}\PYG{o}{+}\PYG{o}{+}
\end{Verbatim}

Por lo tanto en este punto, tenemos todas las celdas inmediatamente
alcanzables desde el \emph{root set} marcadas y con el bit \emph{scan} activado si la
celda puede contener punteros. Por lo tanto solo resta marcar (nuevamente de
forma conservativa) iterativamente todo el \emph{heap} hasta que no hayan más
celdas para visitar (con el bit \emph{scan} activo):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}heap}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{while} \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan}
      \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{false}
      \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
         \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
            \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}}\PYG{o}{=} \PYG{n}{PAGE} \PYG{c+c1}{// saltea FREE y CONTINUATION}
               \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
                  \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{k}{is} \PYG{n+nb}{true}
                     \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{false}
                     \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{PAGE} \PYG{c+c1}{// objeto grande}
                        \PYG{n}{begin} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{page}
                        \PYG{n}{end} \PYG{o}{=} \PYG{n}{find\PYGZus{}big\PYGZus{}object\PYGZus{}end}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)}
                        \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{end}\PYG{p}{)}
                     \PYG{k}{else} \PYG{c+c1}{// objeto pequeño}
                        \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{block}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{block}\PYG{p}{.}\PYG{n}{end}\PYG{p}{)}
\end{Verbatim}

Aquí puede verse, con un poco de esfuerzo, la utilización de la
\hyperlink{gc-intro-tricolor}{\emph{abstracción tricolor}}: todas las celdas alcanzables
desde el \emph{root set} son pintadas de \emph{gris} (tienen los bits \emph{mark} y \emph{scan}
activados), excepto aquellas celdas atómicas (es decir, que se sabe que no
tienen punteros) que son marcadas directamente de \emph{negro}. Luego se van
obteniendo celdas del conjunto de las \emph{grises}, se las pinta de \emph{negro} (es
decir, se desactiva el bit \emph{scan}) y se pintan todas sus \emph{hijas} de \emph{gris} (o
\emph{negro} directamente si no tienen punteros). Este procedimiento se repite
mientras el conjunto de celdas \emph{grises} no sea vacío (es decir, que
\code{more\_to\_scan} sea \code{true}).

A continuación se presenta la implementación de las funciones suplementarias
utilizadas en la fase de marcado:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{find\PYGZus{}big\PYGZus{}object\PYGZus{}end}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pool\PYGZus{}end} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{o}{+} \PYG{p}{(}\PYG{n}{PAGE\PYGZus{}SIZE} \PYG{o}{*} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{k}{do}
      \PYG{n}{page} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{page} \PYG{o}{+} \PYG{n}{PAGE\PYGZus{}SIZE}
   \PYG{k}{while} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{CONTINUATION} \PYG{k}{and} \PYG{n}{page} \PYG{o}{\textless{}} \PYG{n}{pool\PYGZus{}end}
   \PYG{k}{return} \PYG{n}{page}

\PYG{k}{function} \PYG{n}{find\PYGZus{}block}\PYG{p}{(}\PYG{n}{pointer}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{PAGE}
            \PYG{n}{big\PYGZus{}object\PYGZus{}start} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{page}
            \PYG{n}{big\PYGZus{}object\PYGZus{}end} \PYG{o}{=} \PYG{n}{find\PYGZus{}big\PYGZus{}object\PYGZus{}end}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)}
            \PYG{k}{if} \PYG{n}{big\PYGZus{}object\PYGZus{}start} \PYG{o}{\textless{}}\PYG{o}{=} \PYG{n}{pointer} \PYG{o}{\textless{}} \PYG{n}{big\PYGZus{}object\PYGZus{}end}
               \PYG{k}{return} \PYG{p}{[}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{,} \PYG{n}{big\PYGZus{}object\PYGZus{}start}\PYG{p}{]}
         \PYG{k}{else} \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}} \PYG{n}{PAGE}
            \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
               \PYG{n}{block\PYGZus{}start} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{block}
               \PYG{n}{block\PYGZus{}end} \PYG{o}{=} \PYG{n}{block\PYGZus{}start} \PYG{o}{+} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size}
               \PYG{k}{if} \PYG{n}{block\PYGZus{}start} \PYG{o}{\textless{}}\PYG{o}{=} \PYG{n}{pointer} \PYG{o}{\textless{}} \PYG{n}{block\PYGZus{}end}
                  \PYG{k}{return} \PYG{p}{[}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{,} \PYG{n}{block\PYGZus{}start}\PYG{p}{]}
   \PYG{k}{return} \PYG{p}{[}\PYG{n+nb}{null}\PYG{p}{,} \PYG{n+nb}{null}\PYG{p}{,} \PYG{n+nb}{null}\PYG{p}{]}
\end{Verbatim}

Cabe destacar que la función \code{find\_block()} devuelve el \emph{pool}, la página
y el comienzo del bloque al que apunta el puntero, es decir, soporta punteros
\emph{interiores}.
\hypertarget{dgc-algo-sweep}{}

\subsubsection{Fase de barrido}

Esta fase es considerablemente más sencilla que el marcado; el algoritmo puede
dividirse en dos pasos básicos:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{sweep\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{rebuild\PYGZus{}free\PYGZus{}lists}\PYG{p}{(}\PYG{p}{)}
\end{Verbatim}

El barrido se realiza con una pasada por sobre todo el \emph{heap} de la siguiente
manera:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}}\PYG{o}{=} \PYG{n}{PAGE} \PYG{c+c1}{// saltea FREE y CONTINUATION}
            \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
               \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{k}{is} \PYG{n+nb}{false}
                  \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{final} \PYG{k}{is} \PYG{n+nb}{true}
                     \PYG{n}{finalize}\PYG{p}{(}\PYG{n}{block}\PYG{p}{)}
                  \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}
                  \PYG{n}{block}\PYG{p}{.}\PYG{n}{final} \PYG{o}{=} \PYG{n+nb}{false}
                  \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{o}{=} \PYG{n+nb}{false}
                  \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{PAGE} \PYG{c+c1}{// objeto grande}
                     \PYG{n}{free\PYGZus{}big\PYGZus{}object}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)}
\end{Verbatim}

Como se observa, se recorre todo el \emph{heap} en busca de bloques y páginas
libres. Los bloques libres son marcados con el atributo \code{free} y las páginas
libres son marcadas con el tamaño de bloque simbólico \code{FREE}. Para los
objetos grandes se marcan todas las páginas que utilizaban como \code{FREE}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{free\PYGZus{}big\PYGZus{}object}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pool\PYGZus{}end} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{o}{+} \PYG{p}{(}\PYG{n}{PAGE\PYGZus{}SIZE} \PYG{o}{*} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{k}{do}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{FREE}
      \PYG{n}{page} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{page} \PYG{o}{+} \PYG{n}{PAGE\PYGZus{}SIZE}
   \PYG{k}{while} \PYG{n}{page} \PYG{o}{\textless{}} \PYG{n}{pool\PYGZus{}end} \PYG{k}{and} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{CONTINUATION}
\end{Verbatim}

Además, los bloques que tienen en atributo \code{final} son finalizados llamando
a la función \code{finalize()}. Esta función es un servicio que provee la
biblioteca \emph{runtime} y en última instancia llama al destructor del objeto
almacenado en el bloque a liberar.

Una vez marcados todos los bloques y páginas con \code{free}, se procede
a reconstruir las listas de libres. Como parte de este proceso se buscan las
páginas que tengan todos los bloques libres para marcar la página completa
como libre (de manera que pueda utilizarse para albergar otro tamaño de bloque
u objetos grandes de ser necesario):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{rebuild\PYGZus{}free\PYGZus{}lists}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{free\PYGZus{}list} \PYG{k}{in} \PYG{n}{free\PYGZus{}lists}
      \PYG{n}{free\PYGZus{}list}\PYG{p}{.}\PYG{n}{clear}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}} \PYG{n}{PAGE} \PYG{c+c1}{// objetos pequeños}
            \PYG{k}{if} \PYG{n}{is\PYGZus{}page\PYGZus{}free}\PYG{p}{(}\PYG{n}{page}\PYG{p}{)}
               \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{FREE}
            \PYG{k}{else}
               \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
                  \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{k}{is} \PYG{n+nb}{true}
                     \PYG{n}{free\PYGZus{}lists}\PYG{p}{[}\PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size}\PYG{p}{]}\PYG{p}{.}\PYG{n}{link}\PYG{p}{(}\PYG{n}{block}\PYG{p}{)}
\end{Verbatim}

Esta reorganización de listas libres además mejoran la localidad de
referencia y previenen la fragmentación. La localidad de referencia se ve
mejorada debido a que asignaciones de memoria próximas en el tiempo serán
también próximas en espacio porque pertenecerán a la misma página (al menos si
las asignaciones son todas del mismo tamaño). La fragmentación se minimiza por
el mismo efecto, primero se asignarán todos los bloques de la misma página.

A continuación se presenta la implementación de una de las funciones
suplementarias de la fase de barrido:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{is\PYGZus{}page\PYGZus{}free}\PYG{p}{(}\PYG{n}{page}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
      \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{k}{is} \PYG{n+nb}{false}
         \PYG{k}{return} \PYG{n+nb}{false}
   \PYG{k}{return} \PYG{n+nb}{true}
\end{Verbatim}

Las demás funciones suplementarias pertenecen a la manipulación de listas
libres que no son más que operaciones sobre una lista simplemente enlazada. En
la sección \hyperlink{dgc-impl}{\emph{Detalles de implementación}} se verá con más detalles como las implementa el
recolector actual.
\hypertarget{dgc-algo-alloc}{}

\subsubsection{Asignación de memoria}

La asignación de memoria del recolector es relativamente compleja, excepto
cuando se asigna un objeto pequeño y ya existe algún bloque con el tamaño
preciso en la lista de libres. Para el resto de los casos la cantidad de
trabajo que debe hacer el recolector para asignar la memoria es considerable.

El algoritmo de asignación de memoria se puede resumir así:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new}\PYG{p}{(}\PYG{n}{size}\PYG{p}{,} \PYG{n}{attrs}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{find\PYGZus{}block\PYGZus{}size}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}} \PYG{n}{PAGE}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{new\PYGZus{}small}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
   \PYG{k}{else}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{new\PYGZus{}big}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{throw} \PYG{n}{out\PYGZus{}of\PYGZus{}memory}
   \PYG{k}{if} \PYG{n}{final} \PYG{k}{in} \PYG{n}{attrs}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{final} \PYG{o}{=} \PYG{n+nb}{true}
   \PYG{k}{if} \PYG{n}{noscan} \PYG{k}{in} \PYG{n}{attrs}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{o}{=} \PYG{n+nb}{true}
   \PYG{k}{return} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{void}\PYG{o}{*}\PYG{p}{)} \PYG{n}{block}
\end{Verbatim}

La función \code{find\_block\_size()} sencillamente busca el tamaño de bloque se
mejor se ajuste al tamaño solicitado (es decir, el bloque más pequeño lo
suficientemente grande como para poder almacenar el tamaño solicitado). Una
vez más el algoritmo distingue objetos grandes de pequeños. Los pequeños se
asignan de las siguiente manera:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new\PYGZus{}small}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{block} \PYG{o}{=} \PYG{n}{find\PYGZus{}block\PYGZus{}with\PYGZus{}size}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{find\PYGZus{}block\PYGZus{}with\PYGZus{}size}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{n+nb}{null}
         \PYG{n}{new\PYGZus{}pool}\PYG{p}{(}\PYG{p}{)}
         \PYG{n}{block} \PYG{o}{=} \PYG{n}{find\PYGZus{}block\PYGZus{}with\PYGZus{}size}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
   \PYG{k}{return} \PYG{n}{block}
\end{Verbatim}

Se intenta reiteradas veces conseguir un bloque del tamaño correcto libre,
realizando diferentes acciones si no se tiene éxito. Primero se intenta hacer
una \hyperlink{dgc-algo-collect}{\emph{recolección}} y si no se puede encontrar
suficiente espacio luego de ella se intenta crear un nuevo \emph{pool} de memoria
pidiendo memoria al \emph{low level allocator} (el sistema operativo generalmente).

Para intentar buscar un bloque de memoria libre se realiza lo siguiente:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{find\PYGZus{}block\PYGZus{}with\PYGZus{}size}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{block} \PYG{o}{=} \PYG{n}{free\PYGZus{}lists}\PYG{p}{[}\PYG{n}{block\PYGZus{}size}\PYG{p}{]}\PYG{p}{.}\PYG{n}{pop\PYGZus{}first}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{assign\PYGZus{}page}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{free\PYGZus{}lists}\PYG{p}{[}\PYG{n}{block\PYGZus{}size}\PYG{p}{]}\PYG{p}{.}\PYG{n}{pop\PYGZus{}first}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{return} \PYG{n}{block}
\end{Verbatim}

Donde \code{pop\_first()} retorna \code{null} si la lista estaba vacía. Si no se
puede obtener un bloque de la lista de libres correspondiente, se busca
asignar una página libre al tamaño de bloque deseado de forma de \emph{alimentar}
la lista de libres con dicho tamaño:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{assign\PYGZus{}page}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{FREE}
            \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{block\PYGZus{}size}
            \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
               \PYG{n}{free\PYGZus{}lists}\PYG{p}{[}\PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size}\PYG{p}{]}\PYG{p}{.}\PYG{n}{link}\PYG{p}{(}\PYG{n}{block}\PYG{p}{)}
\end{Verbatim}

Cuando todo ello falla, el último recurso consiste en pedir memoria al sistema
operativo, creando un nuevo \emph{pool}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new\PYGZus{}pool}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{l+m+mi}{1}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pool} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{.}\PYG{n}{sizeof}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pool} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{n}{pool}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}
   \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{*} \PYG{n}{PAGE\PYGZus{}SIZE}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{n}{heap}\PYG{p}{.}\PYG{n}{add}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
   \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{FREE}
   \PYG{k}{return} \PYG{n}{pool}
\end{Verbatim}

Se recuerda que la función \code{alloc()} es un \hyperlink{gc-intro-services}{\emph{servicio}} provisto por el \emph{low level allocator} y en la
implementación actual de \href{http://www.digitalmars.com/d/}{D} en general es el sistema operativo (aunque
opcionalmente puede utilizarse la biblioteca estándar de C, que a su vez
utiliza el sistema operativo).

Cualquier error en estas funciones es propagado y en última instancia, cuando
todo falla, la función \code{new()} termina lanzando una excepción indicando que
se agotó la memoria.

Si el tamaño de bloque necesario para cumplir con la asignación de memoria es
de una o más páginas, entonces se utiliza otro algoritmo para alocar un objeto
grande:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new\PYGZus{}big}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{n}{ceil}\PYG{p}{(}\PYG{n}{size} \PYG{o}{/} \PYG{n}{PAGE\PYGZus{}SIZE}\PYG{p}{)}
   \PYG{n}{pages} \PYG{o}{=} \PYG{n}{find\PYGZus{}pages}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{pages} \PYG{o}{=} \PYG{n}{find\PYGZus{}pages}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
         \PYG{n}{minimize}\PYG{p}{(}\PYG{p}{)}
         \PYG{n}{pool} \PYG{o}{=} \PYG{n}{new\PYGZus{}pool}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
         \PYG{k}{if} \PYG{n}{pool} \PYG{k}{is} \PYG{n+nb}{null}
            \PYG{k}{return} \PYG{n+nb}{null}
         \PYG{n}{pages} \PYG{o}{=} \PYG{n}{assign\PYGZus{}pages}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{PAGE}
   \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mf}{1.}\PYG{p}{.}\PYG{n}{end}\PYG{p}{]}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{CONTINUATION}
   \PYG{k}{return} \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}
\end{Verbatim}

De forma similar a la asignación de objetos pequeños, se intenta encontrar una
serie de páginas contiguas, dentro de un mismo \emph{pool}, suficientes para
almacenar el tamaño requerido y si esto falla, se realizan diferentes pasos
y se vuelve a intentar. Puede observarse que, a diferencia de la asignación de
objetos pequeños, si luego de la recolección no se pudo encontrar lugar
suficiente, se trata de minimizar el uso de memoria física utilizando la
siguiente función, que devuelve al \emph{low level allocator} los \emph{pools}
completamente libres:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{minimize}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{n}{all\PYGZus{}free} \PYG{o}{=} \PYG{n+nb}{true}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{k}{not} \PYG{n}{FREE}
            \PYG{n}{all\PYGZus{}free} \PYG{o}{=} \PYG{n+nb}{false}
            \PYG{k}{break}
      \PYG{k}{if} \PYG{n}{all\PYGZus{}free} \PYG{k}{is} \PYG{n+nb}{true}
         \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages}\PYG{p}{)}
         \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
         \PYG{n}{heap}\PYG{p}{.}\PYG{n}{remove}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
\end{Verbatim}

Volviendo a la función \code{new\_big()}, para hallar una serie de páginas
contiguas se utiliza el siguiente algoritmo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{find\PYGZus{}pages}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{n}{pages} \PYG{o}{=} \PYG{n}{assign\PYGZus{}pages}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{pages}
         \PYG{k}{return} \PYG{n}{pages}
   \PYG{k}{return} \PYG{n+nb}{null}
\end{Verbatim}

Como se dijo, las páginas deben estar contenidas en un mismo \emph{pool} (para
tener la garantía de que sean contiguas), por lo tanto se busca \emph{pool} por
\emph{pool} dicha cantidad de páginas libres consecutivas a través del siguiente
algoritmo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{assign\PYGZus{}pages}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pages\PYGZus{}found} \PYG{o}{=} \PYG{l+m+mi}{0}
   \PYG{n}{first\PYGZus{}page} \PYG{o}{=} \PYG{n+nb}{null}
   \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
      \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{FREE}
         \PYG{k}{if} \PYG{n}{pages\PYGZus{}found} \PYG{k}{is} \PYG{l+m+mi}{0}
            \PYG{n}{pages\PYGZus{}found} \PYG{o}{=} \PYG{l+m+mi}{1}
            \PYG{n}{first\PYGZus{}page} \PYG{o}{=} \PYG{n}{page}
         \PYG{k}{else}
            \PYG{n}{pages\PYGZus{}found} \PYG{o}{=} \PYG{n}{pages\PYGZus{}found} \PYG{o}{+} \PYG{l+m+mi}{1}
         \PYG{k}{if} \PYG{n}{pages\PYGZus{}found} \PYG{k}{is} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}
            \PYG{k}{return} \PYG{p}{[}\PYG{n}{first\PYGZus{}page} \PYG{p}{.}\PYG{p}{.} \PYG{n}{page}\PYG{p}{]}
      \PYG{k}{else}
         \PYG{n}{pages\PYGZus{}found} \PYG{o}{=} \PYG{l+m+mi}{0}
         \PYG{n}{first\PYGZus{}page} \PYG{o}{=} \PYG{n+nb}{null}
   \PYG{k}{return} \PYG{n+nb}{null}
\end{Verbatim}

Una vez más, cuando todo ello falla (incluso luego de una recolección), se
intenta alocar un nuevo \emph{pool}, esta vez con una cantidad de páginas
suficientes como para almacenar el objeto grande y si esto falla el error se
propaga hasta la función \code{new()} que lanza una excepción.
\hypertarget{dgc-algo-free}{}

\subsubsection{Liberación de memoria}

La liberación de la memoria asignada puede hacerse explícitamente. Esto
saltea el mecanismo de recolección, y es utilizado para dar soporte a manejo
explícito de memoria asignada en el \emph{heap} del recolector. En general el
usuario no debe utilizar liberación explícita, pero puede ser útil en casos
muy particulares:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{delete}\PYG{p}{(}\PYG{n}{pointer}\PYG{p}{)} \PYG{k}{is}
   \PYG{p}{[}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{,} \PYG{n}{block\PYGZus{}start}\PYG{p}{]} \PYG{o}{=} \PYG{n}{find\PYGZus{}block}\PYG{p}{(}\PYG{n}{pointer}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{k}{not} \PYG{n+nb}{null}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{final} \PYG{o}{=} \PYG{n+nb}{false}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{o}{=} \PYG{n+nb}{false}
      \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{PAGE} \PYG{c+c1}{// objeto grande}
         \PYG{n}{free\PYGZus{}big\PYGZus{}object}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)}
      \PYG{k}{else} \PYG{c+c1}{// objeto pequeño}
         \PYG{n}{free\PYGZus{}lists}\PYG{p}{[}\PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size}\PYG{p}{]}\PYG{p}{.}\PYG{n}{link}\PYG{p}{(}\PYG{n}{block}\PYG{p}{)}
\end{Verbatim}

Como se puede observar, si el objeto es pequeño se enlaza a la lista de libres
correspondiente y si es grande se liberan todas las páginas asociadas a éste,
de forma similar a la \hyperlink{dgc-algo-sweep}{\emph{fase de barrido}}. A diferencia de
ésta, no se finaliza el objeto (es decir, no se llama a su destructor).
\hypertarget{dgc-algo-final}{}

\subsubsection{Finalización}

Al finalizar el programa, el recolector es finalizado también y lo que realiza
actualmente, además de liberar la memoria propia del recolector, es realizar
una recolección. Es decir, si hay objetos que son todavía alcanzables desde el
\emph{root set}, esos objetos no son finalizados (y por lo tanto sus destructores
no son ejecutados).

Como se ha visto, esto es perfectamente válido ya que \href{http://www.digitalmars.com/d/}{D} no garantiza que los
objetos sean finalizados.
\hypertarget{dgc-impl}{}

\subsection{Detalles de implementación}

Hay varias diferencias a nivel de implementación entre lo que se presentó en
las secciones anteriores y como está escrito realmente el recolector actual.
Con los conceptos e ideas principales ya explicadas, se procede a ahondar con
más detalle en como está construido el recolector y algunas de sus
optimizaciones principales.

Vale aclarar que el recolector de basura actual está implementado en \href{http://www.digitalmars.com/d/}{D}.


\subsubsection{Estructuras de datos del recolector}

El recolector está principalmente contenido en la estructura llamada \code{Gcx}.
Dicha estructura tiene los siguientes atributos (divididos en categorías para
facilitar la comprensión):
\begin{description}
\item[{Raíces definidas por el usuario}] \leavevmode\begin{description}
\item[{\emph{roots} (\emph{nroots}, \emph{rootdim})}] \leavevmode\\
Arreglo variable de punteros simples que son tomados como raíces
provistas por el usuario.

\item[{\emph{ranges} (\emph{nranges}, \emph{rangedim})}] \leavevmode\\
Arreglo variable de rangos de memoria que deben ser revisados (de forma
conservativa) como raíces provistas por el usuario. Un rango es una
estructura con dos punteros: \code{pbot} y \code{ptop}. Toda la memoria entre
estos dos punteros se toma, palabra por palabra, como una raíz del
recolector.

\end{description}

\item[{Estado interno del recolector}] \leavevmode\begin{description}
\item[{\emph{anychanges}}] \leavevmode\\
Variable que indica si en la fase de marcado se encontraron nuevas
celdas con punteros que deban ser visitados. Otra forma de verlo es como
un indicador de si el conjunto de celdas \emph{grises} está vacío luego de
una iteración de marcado (utilizando la \hyperlink{gc-intro-tricolor}{\emph{abstracción tricolor}}). Es análoga a la variable \code{more\_to\_scan}
presentada en \hyperlink{dgc-algo-mark}{\emph{Fase de marcado}}.

\item[{\emph{inited} (sic)}] \leavevmode\\
Indica si el recolector fue inicializado.

\item[{\emph{stackBottom}}] \leavevmode\\
Puntero a la base del \emph{stack} (asumiendo que el stack crece hacia arriba).
Se utiliza para saber por donde comenzar a visitar el \emph{stack} de forma
conservativa, tomándolo con una raíz del recolector.

\item[{\emph{Pools} (\emph{pooltable}, \emph{npools})}] \leavevmode\\
Arreglo variable de punteros a estructuras \code{Pool} (ver más adelante).
Este arreglo se mantiene siempre ordenado de menor a mayor según la
dirección de memoria de la primera página que almacena.

\item[{\emph{bucket}}] \leavevmode\\
Listas de libres. Es un arreglo de estructuras \code{List} utilizadas para
guardar la listas de libres de todos los tamaños de bloques posibles (ver
más adelante).

\end{description}

\item[{Atributos que cambian el comportamiento}] \leavevmode\begin{description}
\item[{\emph{noStack}}] \leavevmode\\
Indica que no debe tomarse al \emph{stack} como raíz del recolector. Esto es
muy poco seguro y no debería ser utilizado nunca, salvo casos
extremadamente excepcionales.

\item[{\emph{log}}] \leavevmode\\
Indica si se debe guardar un registro de la actividad del recolector. Es
utilizado principalmente para depuración.

\item[{\emph{disabled}}] \leavevmode\\
Indica que no se deben realizar recolecciones implícitamente. Si al
tratar de asignar memoria no se puede hallar celdas libres en el \emph{heap}
del recolector, se pide más memoria al sistema operativo sin correr una
recolección para intentar recuperar espacio. Esto es particularmente
útil para secciones de un programa donde el rendimiento es crítico y no
se pueden tolerar grandes pausas como las que puede provocar el
recolector.

\end{description}

\item[{Optimizaciones}] \leavevmode\begin{description}
\item[{\emph{p\_cache}, \emph{size\_cache}}] \leavevmode\\
Caché del tamaño de bloque para un puntero dado. Obtener el tamaño de un
bloque es una tarea costosa y común. Para evitarla en casos donde se
calcula de forma sucesiva el tamaño del mismo bloque (como puede ocurrir
al concatenar arreglos dinámicos) se guarda en un caché (de un solo
elemento) el último valor calculado.

\item[{\emph{minAddr}, \emph{maxAddr}}] \leavevmode\\
Punteros al principio y fin del \emph{heap}. Pueden haber \emph{huecos} entre
estos dos punteros que no pertenezcan al \emph{heap} pero siempre se cumple
que si un puntero apunta al \emph{heap} debe estar en este rango. Esto es
útil para hacer un cálculo rápido para descartar punteros que fueron
tomados de forma conservativa y en realidad no apuntan al \emph{heap} (ver la
función \code{find\_block()} en \hyperlink{dgc-algo-mark}{\emph{Fase de marcado}}).

\end{description}

\end{description}


\subsubsection{\emph{Pools}}

La primera diferencia es como está organizado el \emph{heap}. Si bien la
explicación presentada en la sección \hyperlink{dgc-org}{\emph{Organización del heap}} es correcta, la forma en
la que está implementado no es tan \emph{naïve} como los algoritmos presentados en
\hyperlink{dgc-algo}{\emph{Algoritmos del recolector}} sugieren.

El recolector guarda un arreglo variable de estructuras \code{Pool}. Cabe
destacar que para implementar el recolector no se pueden utilizar los arreglos
dinámicos de \href{http://www.digitalmars.com/d/}{D} (ver sección \hyperlink{d-high-level}{\emph{Programación de alto nivel}}) dado que éstos utilizan de
forma implícita el recolector de basura, por lo tanto todos los arreglos
variables del recolector se implementan utilizando las funciones de
C \emph{\texttt{malloc(3)}}, \emph{\texttt{realloc(3)}} y \emph{\texttt{free(3)}}
directamente.

La estructura \code{Pool} está compuesta por los siguientes atributos (ver figura
\vref{fig:dgc-pool}):
\begin{figure}[btp]
\centering

\includegraphics{aafig-bc7dc8b4794266a3dc23c70e96d45aa47d9b2f6c.pdf}
\caption[Vista gráfica de la estructura de un \emph{pool} de memoria]{Vista gráfica de la estructura de un \emph{pool} de memoria.}
\label{fig:dgc-pool}
\end{figure}

\begin{description}
\item[{\emph{baseAddr} y \emph{topAddr}}] \leavevmode\\
Punteros al comienzo y fin de la memoria que almacena todas las páginas del
\emph{pool} (\emph{baseAddr} es análogo al atributo \emph{pages} utilizado en las
secciones anteriores para mayor claridad).

\item[{\emph{mark}, \emph{scan}, \emph{freebits}, \emph{finals}, \emph{noscan}}] \leavevmode\\
Conjuntos de bits (\emph{bitsets}) para almacenar los indicadores descriptos en
\hyperlink{dgc-org}{\emph{Organización del heap}} para todos los bloques de todas las páginas del \emph{pool}.
\emph{freebits} es análogo a \emph{free} y \emph{finals} a \emph{final} en los atributos
descriptos en las secciones anteriores.

\item[{\emph{npages}}] \leavevmode\\
Cantidad de páginas que contiene este \emph{pool} (fue nombrado
\emph{number\_of\_pages} en las secciones anteriores para mayor claridad).

\item[{\emph{ncommitted}}] \leavevmode\\
Cantidad de páginas \emph{encomendadas} al sistema operativo (\emph{committed} en
inglés). Este atributo no se mencionó anteriormente porque el manejo de
páginas encomendadas le agrega una complejidad bastante notable al
recolector y es solo una optimización para un sistema operativo en
particular (Microsoft Windows).

\item[{\emph{pagetable}}] \leavevmode\\
Arreglo de indicadores de tamaño de bloque de cada página de este \emph{pool}.
Los indicadores válidos son \code{B\_16} a \code{B\_2048} (pasando por los valores
posibles de bloque mencionados anteriormente, todos con el prefijo
``\code{B\_}``), \code{B\_PAGE}, \code{B\_PAGEPLUS} (análogo a \code{CONTINUATION}),
\code{B\_UNCOMMITTED} (valor que tienen las páginas que no fueron encomendadas
aún) y \code{B\_FREE}.

\end{description}

Como se observa, además de la información particular del \emph{pool} se almacena
toda la información de páginas y bloques enteramente en el \emph{pool} también.
Esto simplifica el manejo de lo que es memoria \emph{pura} del \emph{heap}, ya que queda
una gran porción continua de memoria sin estar intercalada con
meta-información del recolector.

Para poder acceder a los bits de un bloque en particular, se utiliza la
siguiente cuenta para calcular el índice en el \emph{bitset}:
\begin{gather}
\begin{split}index(p) = \frac{p - baseAddr}{16}\end{split}\notag
\end{gather}
Donde \code{p} es la dirección de memoria del bloque. Esto significa que, sin
importar cual es el tamaño de bloque de las páginas del \emph{pool}, el \emph{pool}
siempre reserva suficientes bits como para que todas las páginas puedan tener
tamaño de bloque de 16 bytes. Esto puede ser desperdiciar bastante espacio si
no predomina un tamaño de bloque pequeño.


\subsubsection{Listas de libres}

Las listas de libres se almacenan en el recolector como un arreglo de
estructuras \code{List}, que se compone solamente de un atributo \code{List* next}
(es decir, un puntero al siguiente). Entonces cada elemento de ese arreglo es
un puntero al primer elemento de la lista en particular.

La implementación utiliza a los bloques de memoria como nodos directamente.
Como los bloques siempre pueden almacenar una palabra (el bloque de menor
tamaño es de 16 bytes y una palabra ocupa comúnmente entre 4 y 8 bytes según
se trabaje sobre arquitecturas de 32 o 64 bits respectivamente), se almacena
el puntero al siguiente en la primera palabra del bloque.


\subsubsection{Algoritmos}

Los algoritmos en la implementación real son considerablemente menos modulares
que los presentados en la sección \hyperlink{dgc-algo}{\emph{Algoritmos del recolector}}. Por ejemplo, la función
\code{collect()} es una gran función de 300 líneas de código fuente.

A continuación se resumen las funciones principales, separadas en categorías
para facilitar la comprensión. Los siguientes son métodos de la estructura
\code{Gcx}:
\begin{description}
\item[{Inicialización y terminación}] \leavevmode\begin{description}
\item[{\emph{initialize()}}] \leavevmode\\
Inicializa las estructuras internas del recolector para que pueda ser
utilizado. Esta función la llama la biblioteca \emph{runtime} antes de que el
programa comience a correr.

\item[{\emph{Dtor()}}] \leavevmode\\
Libera todas las estructuras que utiliza el recolector.

\end{description}

\item[{Manipulación de raíces definidas por el usuario}] \leavevmode\begin{description}
\item[{\emph{addRoot(p)}, \emph{removeRoot(p)}, \emph{rootIter(dg)}}] \leavevmode\\
Agrega, remueve e itera sobre las raíces simples definidas por el
usuario.

\item[{\emph{addRange(pbot, ptop)}, \emph{remove range(pbot)}, \emph{rangeIter(dg)}}] \leavevmode\\
Agrega, remueve e itera sobre los rangos de raíces definidas por el
usuario.

\end{description}

\item[{Manipulación de bits indicadores}] \leavevmode\begin{description}
\item[{\emph{getBits(pool, biti)}}] \leavevmode\\
Obtiene los indicadores especificados para el bloque de índice \code{biti}
en el \emph{pool} \code{pool}.

\item[{\emph{setBits(pool, biti, mask)}}] \leavevmode\\
Establece los indicadores especificados en \code{mask} para el bloque de
índice \code{biti} en el \emph{pool} \code{pool}.

\item[{\emph{clrBits(pool, biti, mask)}}] \leavevmode\\
Limpia los indicadores especificados en \code{mask} para el bloque de
índice \code{biti} en el \emph{pool} \code{pool}.

\end{description}

Cada bloque (\emph{bin} en la terminología de la implementación del recolector)
tiene ciertos indicadores asociados. Algunos de ellos pueden ser
manipulados (indirectamente) por el usuario utilizando las funciones
mencionadas arriba.

El parámetro \code{mask} debe ser una máscara de bits que puede estar
compuesta por la conjunción de los siguientes valores:
\begin{description}
\item[{\emph{FINALIZE}}] \leavevmode\\
El objeto almacenado en el bloque tiene un destructor (indicador
\emph{finals}).

\item[{\emph{NO\_SCAN}}] \leavevmode\\
El objeto almacenado en el bloque no contiene punteros (indicador
\emph{noscan}).

\item[{\emph{NO\_MOVE}}] \leavevmode\\
El objeto almacenado en el bloque no debe ser movido \footnote{
Si bien el recolector actual no tiene la capacidad de mover
objetos, la interfaz del recolector hacer que sea posible una
implementación que lo haga, ya que a través de este indicador se pueden
fijar objetos apuntados desde algún segmento no conservativo (objeto
\emph{pinned}).
}.

\end{description}

\end{description}
\begin{description}
\item[{Búsquedas}] \leavevmode\begin{description}
\item[{\emph{findPool(p)}}] \leavevmode\\
Busca el \emph{pool} al que pertenece el objeto apuntado por \code{p}.

\item[{\emph{findBase(p)}}] \leavevmode\\
Busca la dirección base (el inicio) del bloque apuntado por \code{p}
(\code{find\_block()} según la sección \hyperlink{dgc-algo-mark}{\emph{Fase de marcado}}).

\item[{\emph{findSize(p)}}] \leavevmode\\
Busca el tamaño del bloque apuntado por \code{p}.

\item[{\emph{getInfo(p)}}] \leavevmode\\
Obtiene información sobre el bloque apuntado por \code{p}. Dicha
información se retorna en una estructura \code{BlkInfo} que contiene los
siguientes atributos: \code{base} (dirección del inicio del bloque),
\code{size} (tamaño del bloque) y \code{attr} (atributos o indicadores del
bloque, los que se pueden obtener con \code{getBits()}).

\item[{\emph{findBin(size)}}] \leavevmode\\
Calcula el tamaño de bloque más pequeño que pueda contener un objeto de
tamaño \code{size} (\code{find\_block\_size()} según lo visto en
\hyperlink{dgc-algo-alloc}{\emph{Asignación de memoria}}).

\end{description}

\item[{Asignación de memoria}] \leavevmode\begin{description}
\item[{\emph{reserve(size)}}] \leavevmode\\
Reserva un nuevo \emph{pool} de al menos \code{size} bytes. El algoritmo nunca
crea un \emph{pool} con menos de 256 páginas (es decir, 1 MiB).

\item[{\emph{minimize()}}] \leavevmode\\
Minimiza el uso de la memoria retornando \emph{pools} sin páginas usadas al
sistema operativo.

\item[{\emph{newPool(n)}}] \leavevmode\\
Reserva un nuevo \emph{pool} con al menos \code{n} páginas. Junto con
\code{Pool.initialize()} es análoga a \code{new\_pool()}, solo que esta función
siempre incrementa el número de páginas a, al menos, 256 páginas (es
decir, los \emph{pools} son siempre mayores a 1 MiB). Si la cantidad de
páginas pedidas supera 256, se incrementa el número de páginas en un 50\%
como para que sirva para futuras asignaciones también. Además a medida
que la cantidad de \emph{pools} crece, también trata de obtener cada vez más
memoria. Si ya había un \emph{pool}, el 2do tendrá como mínimo 2 MiB, el 3ro
3 MiB y así sucesivamente hasta 8 MiB. A partir de ahí siempre crea
\emph{pools} de 8 MiB o la cantidad pedida, si ésta es mayor.

\item[{\emph{Pool.initialize(n\_pages)}}] \leavevmode\\
Inicializa un nuevo \emph{pool} de memoria. Junto con \code{newPool()} es
análoga a \code{new\_pool()}. Mientras \code{newPool()} es la encargada de
calcular la cantidad de páginas y crear el objeto \emph{pool}, esta función
es la que pide la memoria al sistema operativo. Además inicializa los
conjuntos de bits: \code{mark}, \code{scan}, \code{freebits}, \code{noscan}.
\code{finals} se inicializa de forma perezosa, cuando se intenta asignar el
atributo \code{FINALIZE} a un bloque, se inicializa el conjunto de bits
\code{finals} de todo el \emph{pool}.

\item[{\emph{allocPage(bin)}}] \leavevmode\\
Asigna a una página libre el tamaño de bloque \code{bin} y enlaza los
nuevos bloques libres a la lista de libres correspondiente (análogo
a \code{assign\_page()}).

\item[{\emph{allocPages(n)}}] \leavevmode\\
Busca \code{n} cantidad de páginas consecutivas libres (análoga
a \code{find\_pages(n)}).

\item[{\emph{malloc(size, bits)}}] \leavevmode\\
Asigna memoria para un objeto de tamaño \code{size} bytes. Análoga al
algoritmo \code{new(size, attr)} presentado, excepto que introduce además
un caché para no recalcular el tamaño de bloque necesario si se realizan
múltiples asignaciones consecutivas de objetos del mismo tamaño y que la
asignación de objetos pequeños no está separada en una función aparte.

\item[{\emph{bigAlloc(size)}}] \leavevmode\\
Asigna un objeto grande (análogo a \code{new\_big()}). La implementación es
mucho más compleja que la presentada en \code{new\_big()}, pero la semántica
es la misma. La única diferencia es que esta función aprovecha que
\code{fullcollectshell()} / \code{fullcollect()} retornan la cantidad de
páginas liberadas en la recolección por lo que puede optimizar levemente
el caso en que no se liberaron suficientes páginas para asignar el
objeto grande y pasar directamente a crear un nuevo \emph{pool}.

\item[{\emph{free(p)}}] \leavevmode\\
Libera la memoria apuntada por \code{p} (análoga a \code{delete()} de la
sección anterior).

\end{description}

Recordar que la \code{pooltable} siempre se mantiene ordenada según la
dirección de la primera página.

\item[{Recolección}] \leavevmode\begin{description}
\item[{\emph{mark(pbot, ptop)}}] \leavevmode\\
Marca un rango de memoria. Este método es análogo al \code{mark\_range()}
presentado en la sección \hyperlink{dgc-algo-mark}{\emph{Fase de marcado}}.

\item[{\emph{fullcollectshell()}}] \leavevmode\\
Guarda los registros del procesador asignado al hilo actual en su
\emph{stack} y llama a \code{fullcollect()}. El resto de los hilos son pausados
y sus registros apilados por la función del \emph{runtime}
\code{thread\_suspendAll()} (y restablecidos y reiniciados por
\code{thread\_resumeAll()}.

\item[{\emph{fullcollect(stackTop)}}] \leavevmode\\
Realiza la recolección de basura. Es análoga a \code{collect()} pero es
considerablemente menos modular, todos los pasos se hacen directamente
en esta función: marcado del \emph{root set}, marcado iterativo del \emph{heap},
barrido y reconstrucción de la lista de libres. Además devuelve la
cantidad de páginas que se liberaron en la recolección, lo que permite
optimizar levemente la función \code{bigAlloc()}.

\end{description}

\end{description}


\subsubsection{Finalización}

El recolector actual, por omisión, solamente efectúa una recolección al
finalizar. Por lo tanto, no se ejecutan los destructores de todos aquellos
objetos que son alcanzables desde el \emph{root set} en ese momento. Existe la
opción de no realizar una recolección al finalizar el recolector, pero no de
finalizar \emph{todos} los objetos (alcanzables o no desde el \emph{root set}). Si bien
la especificación de \href{http://www.digitalmars.com/d/}{D} permite este comportamiento (de hecho la
especificación de \href{http://www.digitalmars.com/d/}{D} es tan vaga que permite un recolector que no llame jamás
a ningún destructor), para el usuario puede ser una garantía muy débil
y proveer finalización asegurada puede ser muy deseable.
\hypertarget{dgc-committed}{}

\subsubsection{Memoria \emph{encomendada}}

El algoritmo actual divide un \emph{pool} en dos áreas: memoria \emph{encomendada}
(\emph{committed} en inglés) y \emph{no-encomendada}. Esto se debe a que originalmente
el compilador de \href{http://www.digitalmars.com/d/}{D} \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} solo funcionaba en Microsoft Windows y este sistema
operativo puede asignar memoria en dos niveles. En principio se puede asignar
al proceso un espacio de memoria (\emph{address space}) pero sin asignarle la
memoria virtual correspondiente. En un paso posterior se puede \emph{encomendar} la
memoria (es decir, asignar realmente la memoria virtual).

Para aprovechar esta característica el recolector diferencia estos dos
niveles. Sin embargo, esta diferenciación introduce una gran complejidad (que
se omitió en las secciones anteriores para facilitar la comprensión),
y convierte lo que es una ventaja en un sistema operativo en una desventaja
para todos los demás (ya que los cálculos extra se realizan pero sin ningún
sentido). De hecho hay sistemas operativos, como \href{http://www.kernel.org/}{Linux}, que realizan este
trabajo automáticamente (la memoria no es asignada realmente al programa hasta
que el programa no haga uso de ella; a esta capacidad se la denomina
\emph{overcommit}).

Como se vio en la figura \vref{fig:dgc-pool}, las páginas de un \emph{pool} se
dividen en \emph{committed} y \emph{uncommitted}. Siempre que el recolector recorre un
\emph{pool} en busca de una página o bloque, lo hace hasta la memoria \emph{committed},
porque la \emph{uncommitted} es como si jamás se hubiera pedido al sistema
operativo a efectos prácticos. Además, al buscar páginas libres, si no se
encuentran entre las \emph{encomendadas} se intenta primero \emph{encomendar} páginas
nuevas antes de crear un nuevo \emph{pool}.


\subsubsection{Sincronización}

Si bien el recolector no es paralelo ni concurrente (ver \hyperlink{gc-art}{\emph{Estado del arte}}),
soporta múltiples \emph{mutator}s. La forma de implementarlo es la más simple.
Todas las operaciones sobre el recolector que se llaman externamente están
sincronizadas utilizando un \emph{lock} global (excepto cuando hay un solo hilo
\emph{mutator}, en cuyo caso se omite la sincronización). Esto afecta también a la
asignación de memoria y cualquier otro servicio provisto por el recolector.
\hypertarget{dgc-good}{}

\subsection{Características destacadas}

Si bien el recolector en términos generales no se aleja mucho de un
\hyperlink{gc-mark-sweep}{\emph{marcado y barrido clásico}}, tiene algunas mejoras por
sobre el algoritmo más básicos que vale la pena destacar:


\subsubsection{Organización del \emph{heap}}

El \emph{heap} está organizado de una forma que, si bien no emplea las técnicas más
modernas que pueden observarse en el estado del arte (como \hyperlink{gc-free-list}{\emph{regiones}}), es relativamente sofisticada. El esquema de \emph{pools}
y bloques permite disminuir considerablemente los problemas de \emph{fragmentación}
de memoria y evita búsquedas de \emph{huecos} que pueden ser costosas (como
\emph{best-fit} \footnote{
Las búsquedas de tipo \emph{best-fit} son aquellas donde se busca
el \emph{hueco} en el \emph{heap} (es decir, una región contínua de memoria
libre) que mejor se ajuste al tamaño del objeto a asignar. Es decir, el
\emph{hueco} más pequeño lo suficientemente grande como para almacenarlo.
}) o desperdiciar mucho espacio (como \emph{first-fit}
\footnote{
Las búsquedas de tipo \emph{first-fit} son aquellas donde se busca
el primer \emph{hueco} en el \emph{heap} (es decir, una región contínua de memoria
libre) que sea lo suficientemente grande como para almacenar el objeto
a asignar.
}), logrando un buen equilibrio entre velocidad y espacio
desperdiciado.


\subsubsection{Fase de marcado iterativa}

A diferencia del algoritmo clásico recursivo, el algoritmo del recolector
actual es iterativo. El algoritmo recursivo tiene un problema fundamental: se
puede llegar a un desbordamiento de pila (o \emph{stack overflow}). La cantidad de
recursiones necesarias es, en el peor caso, $O(|Live \thickspace set|)$
(por ejemplo, si todas las celdas del \emph{heap} formaran una lista simplemente
enlazada). Hay muchas técnicas para lidiar con este problema, algunas que
podrían aplicarse a \href{http://www.digitalmars.com/d/}{D} y otras que no (como \emph{pointer reversal}) \hyperlink{joli96}{{[}JOLI96{]}}. El
recolector actual, sin embargo, cambia complejidad en espacio por complejidad
en tiempo, utilizando un algoritmo iterativo que es constante ($O(1)$)
en espacio, pero que requiere varias pasada sobre el \emph{heap} en vez de una (la
cantidad de pasadas en el peor caso es $O(|Live \thickspace set|)$, al
igual que la profundidad del algoritmo recursivo, pero cada pasada se realiza
sobre todo el \emph{heap}).


\subsubsection{Conjuntos de bits para indicadores}

El algoritmo clásico propone almacenar en la propia celda la marca (para la
fase de marcado) y otros indicadores. El algoritmo del recolector actual
utiliza conjuntos de bits. Esto trae dos ventajas principales:
\begin{itemize}
\item {} 
Permite minimizar el espacio requerido, ya que de otra forma en general se
desperdicia una palabra entera como cabecera de celda para guardar este tipo
de información.

\item {} 
Mejora la localidad de referencia, ya que los indicadores se escriben de
forma muy compacta y en una región de memoria contigua que generalmente
puede entrar en el cache o en pocas páginas de memoria acelerando
considerablemente la fase de marcado.

\end{itemize}
\hypertarget{dgc-debug}{}

\subsubsection{Herramientas para depuración}

El recolector provee algunas opciones para simplificar el diagnóstico
y depuración de problemas, tanto del mismo recolector como del programa del
usuario.

Las opciones más importantes son:
\begin{description}
\item[{\code{MEMSTOMP}}] \leavevmode\\
Su función es escribir un patrón determinado de bits en todos los bytes de
un bloque de memoria según se haya:
\begin{itemize}
\item {} 
Pedido un bloque menor a una página (\code{0xF0}).

\item {} 
Pedido un bloque mayor a una página (\code{0xF1}).

\item {} 
Dejado de usar debido a un pedido de achicamiento de un bloque
(\code{0xF2}).

\item {} 
Pedido más páginas debido a un pedido de agrandamiento de un bloque
(\code{0xF0}).

\item {} 
Liberado intencionalmente por el usuario (\code{0xF2}).

\item {} 
Barrido (\code{0xF3}).

\end{itemize}

Esto permite al diagnosticar un problema saber, por ejemplo, si un
determinado área de memoria fue recolectada recientemente, o liberada por
el usuario, o recién adquirida, etc. con tan solo ver si un patrón de bits
determinado está presente. Por supuesto puede existir \emph{falsos positivos}
pero su probabilidad es lo suficientemente baja como para que sea útil en
la práctica.

\item[{\code{SENTINEL}}] \leavevmode\\
Su función detectar errores producidos por escribir más allá (o antes) del
área de memoria solicitada. Está implementado reservando un poco más de
memoria de la que pide el usuario y devolviendo un puntero a un bloque
ubicado dentro del bloque real reservado (en vez de al inicio). Escribiendo
un patrón de bits en los extremos del bloque real (ver figura
\vref{fig:sentinel}) se puede verificar, en distintas situaciones (como
por ejemplo al barrer el bloque), que esas guardas con los patrones de bits
estén intactas (en caso contrario se ha escrito por fuera de los límites
del bloque solicitado). Esto permite detectar de forma temprana errores
tanto en el recolector como en el programa del usuario.
\begin{figure}[btp]
\centering

\includegraphics{aafig-5edcbe07f64ef212e4fa9b5ad2a7d6ed374dfbe0.pdf}
\caption[Esquema de un bloque cuando está activada la opción \code{SENTINEL}]{Esquema de un bloque cuando está activada la opción \code{SENTINEL}.}
\label{fig:sentinel}
\end{figure}


\end{description}

Ambas opciones son seleccionables sólo en tiempo de compilación del
recolector, por lo que su utilidad real, al menos para el usuario, se ve
severamente reducida.
\hypertarget{dgc-bad}{}

\subsection{Problemas y limitaciones}

A continuación se presentan los principales problemas encontrados en la
implementación actual del recolector de basura de \href{http://www.digitalmars.com/d/}{D}. Estos problemas surgen
principalmente de la observación del código y de aproximadamente tres años de
participación y observación del grupo de noticias, de donde se obtuvieron los
principales problemas percibidos por la comunidad que utiliza el lenguaje.


\hypertarget{dgc-bad-code}{}\subsubsection{Complejidad del código y documentación}

El análisis del código fue muy complicado debido a la falta de documentación
y desorganización del código. Además se nota que el recolector ha sido escrito
en una fase muy temprana y que a ido evolucionando a partir de ello de forma
descuidada y sin ser rescrito nunca para aprovechar las nuevas características
que el lenguaje fue incorporando (por ejemplo \emph{templates}).

Estos dos problemas (código complicado y falta de documentación) producen un
efecto de círculo vicioso, porque provocan que sea complejo entender el
recolector actual y en consecuencia sea muy complicado escribir documentación
o mejorarlo. Esto a su vez provoca que, al no disponer de una implementación
de referencia sencilla, sea muy difícil implementar un recolector nuevo.

Este es, probablemente, la raíz de todos los demás problemas del recolector
actual. Para ilustrar la dimensión del problema se presenta la implementación
real de la función \code{bigAlloc()}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{c+cm}{/**}
\PYG{c+cm}{ * Allocate a chunk of memory that is larger than a page.}
\PYG{c+cm}{ * Return null if out of memory.}
\PYG{c+cm}{ */}
\PYG{k+kt}{void} \PYG{p}{*}\PYG{n}{bigAlloc}\PYG{p}{(}\PYG{n}{size\PYGZus{}t} \PYG{n}{size}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
    \PYG{n}{Pool}\PYG{p}{*}  \PYG{n}{pool}\PYG{p}{;}
    \PYG{n}{size\PYGZus{}t} \PYG{n}{npages}\PYG{p}{;}
    \PYG{n}{size\PYGZus{}t} \PYG{n}{n}\PYG{p}{;}
    \PYG{n}{size\PYGZus{}t} \PYG{n}{pn}\PYG{p}{;}
    \PYG{n}{size\PYGZus{}t} \PYG{n}{freedpages}\PYG{p}{;}
    \PYG{k+kt}{void}\PYG{p}{*}  \PYG{n}{p}\PYG{p}{;}
    \PYG{k+kt}{int}    \PYG{n}{state}\PYG{p}{;}

    \PYG{n}{npages} \PYG{p}{=} \PYG{p}{(}\PYG{n}{size} \PYG{p}{+} \PYG{n}{PAGESIZE} \PYG{p}{-} \PYG{l+m+mi}{1}\PYG{p}{)} \PYG{p}{/} \PYG{n}{PAGESIZE}\PYG{p}{;}

    \PYG{k}{for} \PYG{p}{(}\PYG{n}{state} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{p}{;} \PYG{p}{)}
    \PYG{p}{\PYGZob{}}
        \PYG{c+c1}{// This code could use some refinement when repeatedly}
        \PYG{c+c1}{// allocating very large arrays.}

        \PYG{k}{for} \PYG{p}{(}\PYG{n}{n} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{n}{n} \PYG{p}{\textless{}} \PYG{n}{npools}\PYG{p}{;} \PYG{n}{n}\PYG{p}{++}\PYG{p}{)}
        \PYG{p}{\PYGZob{}}
            \PYG{n}{pool} \PYG{p}{=} \PYG{n}{pooltable}\PYG{p}{[}\PYG{n}{n}\PYG{p}{]}\PYG{p}{;}
            \PYG{n}{pn} \PYG{p}{=} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{allocPages}\PYG{p}{(}\PYG{n}{npages}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{if} \PYG{p}{(}\PYG{n}{pn} \PYG{p}{!=} \PYG{n}{OPFAIL}\PYG{p}{)}
                \PYG{k}{goto} \PYG{n}{L1}\PYG{p}{;}
        \PYG{p}{\PYGZcb{}}

        \PYG{c+c1}{// Failed}
        \PYG{k}{switch} \PYG{p}{(}\PYG{n}{state}\PYG{p}{)}
        \PYG{p}{\PYGZob{}}
        \PYG{k}{case} \PYG{l+m+mi}{0}\PYG{p}{:}
            \PYG{k}{if} \PYG{p}{(}\PYG{n}{disabled}\PYG{p}{)}
            \PYG{p}{\PYGZob{}}   \PYG{n}{state} \PYG{p}{=} \PYG{l+m+mi}{1}\PYG{p}{;}
                \PYG{k}{continue}\PYG{p}{;}
            \PYG{p}{\PYGZcb{}}
            \PYG{c+c1}{// Try collecting}
            \PYG{n}{freedpages} \PYG{p}{=} \PYG{n}{fullcollectshell}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{if} \PYG{p}{(}\PYG{n}{freedpages} \PYG{p}{\textgreater{}=} \PYG{n}{npools} \PYG{p}{*} \PYG{p}{(}\PYG{p}{(}\PYG{n}{POOLSIZE} \PYG{p}{/} \PYG{n}{PAGESIZE}\PYG{p}{)} \PYG{p}{/} \PYG{l+m+mi}{4}\PYG{p}{)}\PYG{p}{)}
            \PYG{p}{\PYGZob{}}   \PYG{n}{state} \PYG{p}{=} \PYG{l+m+mi}{1}\PYG{p}{;}
                \PYG{k}{continue}\PYG{p}{;}
            \PYG{p}{\PYGZcb{}}
            \PYG{c+c1}{// Release empty pools to prevent bloat}
            \PYG{n}{minimize}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
            \PYG{c+c1}{// Allocate new pool}
            \PYG{n}{pool} \PYG{p}{=} \PYG{n}{newPool}\PYG{p}{(}\PYG{n}{npages}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{if} \PYG{p}{(}\PYG{p}{!}\PYG{n}{pool}\PYG{p}{)}
            \PYG{p}{\PYGZob{}}   \PYG{n}{state} \PYG{p}{=} \PYG{l+m+mi}{2}\PYG{p}{;}
                \PYG{k}{continue}\PYG{p}{;}
            \PYG{p}{\PYGZcb{}}
            \PYG{n}{pn} \PYG{p}{=} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{allocPages}\PYG{p}{(}\PYG{n}{npages}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{assert}\PYG{p}{(}\PYG{n}{pn} \PYG{p}{!=} \PYG{n}{OPFAIL}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{goto} \PYG{n}{L1}\PYG{p}{;}
        \PYG{k}{case} \PYG{l+m+mi}{1}\PYG{p}{:}
            \PYG{c+c1}{// Release empty pools to prevent bloat}
            \PYG{n}{minimize}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
            \PYG{c+c1}{// Allocate new pool}
            \PYG{n}{pool} \PYG{p}{=} \PYG{n}{newPool}\PYG{p}{(}\PYG{n}{npages}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{if} \PYG{p}{(}\PYG{p}{!}\PYG{n}{pool}\PYG{p}{)}
                \PYG{k}{goto} \PYG{n}{Lnomemory}\PYG{p}{;}
            \PYG{n}{pn} \PYG{p}{=} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{allocPages}\PYG{p}{(}\PYG{n}{npages}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{assert}\PYG{p}{(}\PYG{n}{pn} \PYG{p}{!=} \PYG{n}{OPFAIL}\PYG{p}{)}\PYG{p}{;}
            \PYG{k}{goto} \PYG{n}{L1}\PYG{p}{;}
        \PYG{k}{case} \PYG{l+m+mi}{2}\PYG{p}{:}
            \PYG{k}{goto} \PYG{n}{Lnomemory}\PYG{p}{;}
        \PYG{k}{default}\PYG{p}{:}
            \PYG{k}{assert}\PYG{p}{(}\PYG{k+kc}{false}\PYG{p}{)}\PYG{p}{;}
        \PYG{p}{\PYGZcb{}}
    \PYG{p}{\PYGZcb{}}

  \PYG{n}{L1}\PYG{p}{:}
    \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pagetable}\PYG{p}{[}\PYG{n}{pn}\PYG{p}{]} \PYG{p}{=} \PYG{n}{B\PYGZus{}PAGE}\PYG{p}{;}
    \PYG{k}{if} \PYG{p}{(}\PYG{n}{npages} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{1}\PYG{p}{)}
        \PYG{n}{cstring}\PYG{p}{.}\PYG{n}{memset}\PYG{p}{(}\PYG{p}{\&}\PYG{n}{pool}\PYG{p}{.}\PYG{n}{pagetable}\PYG{p}{[}\PYG{n}{pn} \PYG{p}{+} \PYG{l+m+mi}{1}\PYG{p}{]}\PYG{p}{,} \PYG{n}{B\PYGZus{}PAGEPLUS}\PYG{p}{,} \PYG{n}{npages} \PYG{p}{-} \PYG{l+m+mi}{1}\PYG{p}{)}\PYG{p}{;}
    \PYG{n}{p} \PYG{p}{=} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{baseAddr} \PYG{p}{+} \PYG{n}{pn} \PYG{p}{*} \PYG{n}{PAGESIZE}\PYG{p}{;}
    \PYG{n}{cstring}\PYG{p}{.}\PYG{n}{memset}\PYG{p}{(}\PYG{k}{cast}\PYG{p}{(}\PYG{k+kt}{char} \PYG{p}{*}\PYG{p}{)}\PYG{n}{p} \PYG{p}{+} \PYG{n}{size}\PYG{p}{,} \PYG{l+m+mi}{0}\PYG{p}{,} \PYG{n}{npages} \PYG{p}{*} \PYG{n}{PAGESIZE} \PYG{p}{-} \PYG{n}{size}\PYG{p}{)}\PYG{p}{;}
    \PYG{k}{debug} \PYG{p}{(}\PYG{n}{MEMSTOMP}\PYG{p}{)} \PYG{n}{cstring}\PYG{p}{.}\PYG{n}{memset}\PYG{p}{(}\PYG{n}{p}\PYG{p}{,} \PYG{l+m+mh}{0xF1}\PYG{p}{,} \PYG{n}{size}\PYG{p}{)}\PYG{p}{;}
    \PYG{c+c1}{//debug(PRINTF) printf("\PYGZbs{}tp = \%x\PYGZbs{}n", p);}
    \PYG{k}{return} \PYG{n}{p}\PYG{p}{;}

  \PYG{n}{Lnomemory}\PYG{p}{:}
    \PYG{k}{return} \PYG{k+kc}{null}\PYG{p}{;} \PYG{c+c1}{// let mallocNoSync handle the error}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

Se recuerda que la semántica de dicha función es la misma que la de la función
\code{new\_big()} presentada en \hyperlink{dgc-algo-alloc}{\emph{Asignación de memoria}}.

Además, como se comentó en la sección anterior, los algoritmos en la
implementación real son considerablemente menos modulares que los presentados
en la sección \hyperlink{dgc-algo}{\emph{Algoritmos del recolector}}. Por ejemplo, la función \code{fullcollect()} tiene
300 líneas de código fuente.


\subsubsection{Memoria \emph{encomendada}}

Como se comentó en la sección anterior, diferenciar entre memoria
\emph{encomendada} de memoria \emph{no-encomendada} es complejo y levemente costoso (en
particular para sistemas operativos que no hacen esta distinción, al menos
explícitamente, donde no hay ningún beneficio en realizar esta distinción).

Incluso para Microsoft Windows, la ventaja de realizar esta distinción debería
ser comprobada.


\subsubsection{Precisión}

Este fue históricamente uno de los problemas principales del recolector de \href{http://www.digitalmars.com/d/}{D}
\hyperlink{ngd46407}{{[}NGD46407{]}} \hyperlink{ngd35364}{{[}NGD35364{]}}. Sin embargo, desde que, en la versión 1.001, se ha
incorporado la capacidad de marcar un bloque como de datos puros (no contiene
punteros, el atributo \code{NO\_SCAN}) \hyperlink{nga6842}{{[}NGA6842{]}}, la gravedad de esos problemas ha
disminuido considerablemente, aunque siguieron reportándose problemas más
esporádicamente \hyperlink{ngd54084}{{[}NGD54084{]}} \hyperlink{ngl13744}{{[}NGL13744{]}}.

De todas maneras queda mucho lugar para mejoras, y es un tema recurrente en el
grupo de noticias de \href{http://www.digitalmars.com/d/}{D} y se han discutido formas de poder hacer que, al menos
el \emph{heap} sea preciso \hyperlink{ngd44607}{{[}NGD44607{]}} \hyperlink{ngd29291}{{[}NGD29291{]}}. Además se mostró un interés
general por tener un recolector más preciso \hyperlink{ngd87831}{{[}NGD87831{]}}, pero no han habido
avances al respecto hasta hace muy poco tiempo.

Otra forma de minimizar los efectos de la falta de precisión que se ha
sugerido reiteradamente en el grupo es teniendo la
posibilidad de indicar cuando no pueden haber punteros interiores a un bloque
\hyperlink{ngd89394}{{[}NGD89394{]}} \hyperlink{ngd71869}{{[}NGD71869{]}}. Esto puede ser de gran utilidad para objetos grandes
y en particular para mejorar la implementación de de arreglos asociativos.


\subsubsection{Referencias débiles}

Si bien el recolector de \href{http://www.dsource.org/projects/tango}{Tango} tiene un soporte limitado de \emph{referencias
débiles} \footnote{
Una referencia débil (o \emph{weak reference} en inglés) es
aquella que que no protege al objeto referenciado de ser reciclado por el
recolector.
}, el de \href{http://www.dsource.org/projects/phobos}{Phobos} no dispone de ningún soporte (por lo
tanto no está contemplado oficialmente el lenguaje).  Sin embargo hay una
demanda apreciable \hyperlink{ngd86840}{{[}NGD86840{]}} \hyperlink{ngd13301}{{[}NGD13301{]}} \hyperlink{ngl8264}{{[}NGL8264{]}} \hyperlink{ngd69761}{{[}NGD69761{]}} \hyperlink{ngd74624}{{[}NGD74624{]}}
\hyperlink{ngd88065}{{[}NGD88065{]}}.

Para cubrir esta demanda, se han implementado soluciones como biblioteca para
suplir la inexistencia de una implementación oficial \hyperlink{nga9103}{{[}NGA9103{]}} (la
implementación de \href{http://www.dsource.org/projects/tango}{Tango} es otro ejemplo).

Sin embargo éstas son en general poco robustas, extremadamente dependientes de
la implementación del recolector y, en general, presentan problemas muy
sutiles \hyperlink{ngd88065}{{[}NGD88065{]}}. Por esta razón se ha discutido la posibilidad de incluir
la implementación de \emph{referencias débiles} como parte del lenguaje
\hyperlink{ngd88559}{{[}NGD88559{]}}.


\subsubsection{Concurrencia}

El soporte actual de concurrencia, en todos sus aspectos, es muy primitivo. El
recolector apenas soporta múltiples \emph{mutators} pero con un nivel de
sincronización excesivo.

Se ha sugerido en el pasado el uso de \emph{pools} y listas de libres específicos
de hilos, de manera de disminuir la contención, al menos para la asignación de
memoria \hyperlink{ngd75952}{{[}NGD75952{]}} \hyperlink{ngd87831}{{[}NGD87831{]}}.

Además se ha mostrado un interés por tener un nivel de concurrencia aún mayor
en el recolector, para aumentar la eficiencia en ambientes \emph{multi-core} en
general pero en particular para evitar grandes pausas en programas con
requerimientos de tiempo real, históricamente una de las principales críticas
al lenguaje \hyperlink{ngd87831}{{[}NGD87831{]}} \hyperlink{ngl3937}{{[}NGL3937{]}} \hyperlink{ngd22968}{{[}NGD22968{]}} \hyperlink{nga15246}{{[}NGA15246{]}} \hyperlink{ngd5622}{{[}NGD5622{]}}
\hyperlink{ngd2547}{{[}NGD2547{]}} \hyperlink{ngd18354}{{[}NGD18354{]}}.


\subsubsection{Finalización}

El recolector actual no garantiza la finalización de objetos. En particular
los objetos no son finalizados (es decir, no se llama a sus destructores) si
aún alcanzables desde el \emph{root set} cuando el programa termina. Cabe destacar
que esto puede darse porque hay una referencia real desde el \emph{root set} (en
cuyo caso queda bajo el control del usuario) pero también, dado que el \emph{root
set} se visita de forma conservativa, se puede deber a un \emph{falso positivo}, en
cuyo caso la omisión de la finalización queda por completo fuera del control
del usuario (y lo que es aún peor, el usuario no puede ser siquiera notificado
de esta anomalía).

Si bien la especificación de \href{http://www.digitalmars.com/d/}{D} no requiere esta capacidad, no hay mayores
problemas para implementar un recolector que dé este tipo de garantías
\hyperlink{ngd88298}{{[}NGD88298{]}}.

Además los objetos pueden ser finalizados tanto determinísticamente
(utilizando \code{delete} o \code{scope}; ver secciones \hyperlink{d-low-level}{\emph{Programación de bajo nivel (system programming)}}
y \hyperlink{d-dbc}{\emph{Programación confiable}}) como no determinísticamente (cuando son finalizados por el
recolector). En el primer caso se puede, por ejemplo, acceder sus atributos
u otra memoria que se conozca \emph{viva}, mientras que en el segundo no. Sin
embargo un destructor no puede hacer uso de esta distinción, haciendo que la
finalización determinística tenga a fines prácticos las mismas restricciones
que la finalización no determinística. Es por esto que se ha sugerido permitir
al destructor distinguir estos dos tipos de finalización \hyperlink{ngd89302}{{[}NGD89302{]}}.


\subsubsection{Eficiencia}

El rendimiento en general del recolector es una de las críticas frecuentes. Si
bien hay muchos problemas que han sido resueltos, en especial por la inclusión
de un mínimo grado de precisión en la versión 1.001, en la actualidad se
siguen encontrando en el grupo de noticias críticas respecto a esto
\hyperlink{ngd43991}{{[}NGD43991{]}} \hyperlink{ngd67673}{{[}NGD67673{]}} \hyperlink{ngd63541}{{[}NGD63541{]}} \hyperlink{ngd90977}{{[}NGD90977{]}}.

La principal causa del bajo rendimiento del recolector actual es,
probablemente, lo simple de su algoritmo principal de recolección. Más allá de
una organización del \emph{heap} moderadamente apropiada y de utilizar conjuntos de
bits para la fase de marcado, el resto del algoritmo es casi la versión más
básica de marcado y barrido. Hay mucho lugar para mejoras en este sentido.


\subsubsection{Configurabilidad}

Si bien el recolector actual tiene algunas características configurables,
todas son seleccionables sólo en tiempo de compilación del recolector (no del
programa del usuario), como por ejemplo las opciones descriptas en
\hyperlink{dgc-debug}{\emph{Herramientas para depuración}}. Por lo tanto, a nivel práctico, es como si no tuviera
posibilidad alguna de ser configurado por el usuario, ya que no es parte del
ciclo de desarrollo normal el recompilar el recolector o \emph{runtime} de un
lenguaje.

Dado que es imposible que un recolector sea óptimo para todo tipo de
programas, es muy deseable permitir una configuración de parámetros del
recolector que permitan al usuario ajustarlos a las necesidades particulares
de sus aplicaciones.
\hypertarget{dgc-bad-ocup}{}

\subsubsection{Factor de ocupación del \emph{heap}}

Otro problema potencialmente importante del recolector actual es que no se
tiene ningún cuidado con respecto a que, luego de una recolección, se haya
recuperado una buena parte del \emph{heap}. Por lo tanto, en casos extremos, el
recolector tiene que hacer una recolección por cada petición de memoria, lo
que es extremadamente ineficiente.

Para evitar esto, habría que usar algún esquema para evaluar cuando una
recolección no fue lo suficientemente \emph{exitosa} y en ese caso pedir más
memoria al sistema operativo.


\subsubsection{Detalles}

Finalmente hay varios detalles en la implementación actual que podrían
mejorarse:
\begin{description}
\item[{Listas de libres}] \leavevmode\\
Hay 12 listas de libres, como para guardar bloques de tamaño de \code{B\_16}
a \code{B\_2048}, \code{B\_PAGE}, \code{B\_PAGEPLUS}, \code{B\_UNCOMMITTED} y \code{B\_FREE};
sin embargo solo tienen sentido los bloques de tamaño \code{B\_16}
a \code{B\_2048}, por lo que 4 de esas listas no se utilizan.

\item[{Conjuntos de bits para indicadores}] \leavevmode\\
Los indicadores para la fase de marcado y otras propiedades de un bloque
son almacenados en conjuntos de bits que almacenan los indicadores de todos
los bloques de un \emph{pool}. Si bien se ha mencionado esto como una ventaja,
hay lugar todavía como para algunas mejoras. Como un \emph{pool} tiene páginas
con distintos tamaños de bloque, se reserva una cantidad de bits igual a la
mayor cantidad posible de bloques que puede haber en el \emph{pool}; es decir,
se reserva 1 bit por cada 16 bytes del \emph{pool}. Para un \emph{pool} de 1 MiB
(tamaño mínimo), teniendo en cuenta que se utilizan 5 conjuntos de bits
(\code{mark}, \code{scan}, \code{finals}, \code{freebits} y \code{noscan}), se utilizan 40
KiB de memoria para conjuntos de bits (un 4\% de \emph{desperdicio} si, por
ejemplo, ese \emph{pool} estuviera destinado por completo a albergar un solo
objeto grande; lo que equivaldría al 2560 objetos de 16 bytes
desperdiciados en bits inutilizados).

\item[{Repetición de código}] \leavevmode\\
Hay algunos fragmentos de código repetidos innecesariamente. Por ejemplo en
varios lugares se utilizan arreglos de tamaño variable que se implementan
repetidas veces (en general como un puntero al inicio del arreglo más el
tamaño actual del arreglo más el tamaño de la memoria total asignada
actualmente). Esto es propenso a errores y difícil de mantener.

\item[{Uso de señales}] \leavevmode\\
El recolector actual utiliza las señales del sistema operativo \code{SIGUSR1}
y \code{SIGUSR2} para pausar y reanudar los hilos respectivamente. Esto
puede traer inconvenientes a usuarios que desean utilizar estas
señales en sus programas (o peor aún, si interactúan con bibliotecas
de C que hacen uso de estas señales) \hyperlink{ngd5821}{{[}NGD5821{]}}.

\item[{Marcado iterativo}] \leavevmode\\
Si bien esto se mencionó como algo bueno del recolector actual, es un
compromiso entre tiempo y espacio, y puede ser interesante analizar otros
métodos para evitar la recursión que no requieran tantas pasadas sobre el
\emph{heap}.

\end{description}
\hypertarget{dgc-via}{}

\section{Análisis de viabilidad}

Ya conociendo el lenguaje de programación \href{http://www.digitalmars.com/d/}{D} (con sus necesidades
particulares), el estado del arte en recolección de basura  y el recolector
actual de \href{http://www.digitalmars.com/d/}{D} es posible evaluar la viabilidad de los distintos algoritmos
vistos en el capítulo \hyperlink{gc}{\emph{Recolección de basura}}. Se recuerda que dentro del análisis de
viabilidad de considera de gran importancia la viabilidad social y política de
la mejora, es decir, se presta particular atención en encontrar una mejora que
tenga una buena probabilidad de ser aceptada por la comunidad de \href{http://www.digitalmars.com/d/}{D}.


\hypertarget{dgc-via-classic}{}\subsection{Algoritmos clásicos}

En esta sección se presenta un análisis de los \hyperlink{gc-classic}{\emph{algoritmos clásicos}}, de forma de poder analizar a grandes rasgos las principales
familias para ir determinando la dirección principal de la solución.


\hypertarget{dgc-via-rc}{}\subsubsection{Conteo de referencias}

Ya se ha propuesto en el pasado la utilización de conteo de referencias en \href{http://www.digitalmars.com/d/}{D}
pero no se ha demostrado un interés real, más allá de soluciones en
bibliotecas \hyperlink{ngd38689}{{[}NGD38689{]}}. Las razones para no utilizar conteo de referencia son
más o menos las mismas que las desventajas mencionadas en la sección
\hyperlink{gc-rc}{\emph{Conteo de referencias}} (en el capítulo \hyperlink{gc}{\emph{Recolección de basura}}), siendo la principal la incapacidad de
recolectar ciclos. Sin embargo hay otras razones importantes.

Una de ellas es la inter-operatividad con C. El utilizar un contador de
referencias requiere la manipulación del contador por parte del código C con
el que se interactúe. Si bien este problema ya está presente si código
C guarda en su \emph{headp} un puntero a un objeto almacenado en el \emph{heap} del
recolector de \href{http://www.digitalmars.com/d/}{D}, esto es poco común. Sin embargo, mientras que una función de
C se está ejecutando, es extremadamente común que pueda almacenar en el
\emph{stack} una referencia a un objeto de \href{http://www.digitalmars.com/d/}{D} y en ese caso el recolector actual
puede manejarlo (mientras la función de C esté corriendo en un hilo creado por
\href{http://www.digitalmars.com/d/}{D}). Sin embargo al usar un conteo de referencias esto es más problemático, ya
que no se mantiene la invariante del algoritmo si no son actualizados siempre
los contadores.

Otro problema es que al liberarse una celda, existe la posibilidad de tener
que liberar todo el sub-grafo conectado a ésta. Cuando este sub-grafo es
grande, se puede observar una gran pausa.

Si bien estas razones son suficientes como para considerar que el conteo de
referencias no es un algoritmo que sea viable en \href{http://www.digitalmars.com/d/}{D}, hay muchas técnicas
y optimizaciones para minimizarlas (como liberación perezosa, conteo de
referencias pospuesto, etc. \hyperlink{joli96}{{[}JOLI96{]}}). Sin embargo hay otra razón importante
que descarta esta familia de algoritmos ya que todas las variaciones de conteo
de referencias implican, en mayor o menor medida, el entrelazado del trabajo
del recolector con el del \emph{mutator}. Si bien esta es una característica en
general muy deseable (porque hace que el recolector sea \hyperlink{gc-inc}{\emph{incremental}}), en \href{http://www.digitalmars.com/d/}{D} no lo es porque tiene como requerimiento no hacer pagar el
precio de cosas que no se usan. En \href{http://www.digitalmars.com/d/}{D} debe ser posible no utilizar el
recolector de basura y, al no hacerlo, no tener ningún tipo de trabajo extra
asociado a éste. De usarse conteo de referencias esto no sería posible.

Si bien este requerimiento puede ser discutible técnicamente, hay una gran
resistencia social y política ante cualquier tipo de recolector que imponga
una penalización de rendimiento a alguien que no quiera usarlo \hyperlink{ngd38689}{{[}NGD38689{]}}.
Además requiere un cambio complejo y profundo en el compilador, siendo éste
uno de los eslabones con mayor resistencia a introducir cambios.

Por lo tanto se concluye que el conteo de referencias no es un algoritmo
viable para este trabajo.
\hypertarget{dgc-via-mark-sweep}{}

\subsubsection{Marcado y barrido}

El marcado y barrido es un algoritmo evidentemente viable debido a que es la
base del algoritmo del recolector de basura actual.

En general en la comunidad de \href{http://www.digitalmars.com/d/}{D} no hay mayores críticas al marcado y barrido
en sí, si no más bien a problemas asociados a la implementación actual,
principalmente a las grandes pausas o la falta de \hyperlink{gc-conserv}{\emph{precisión}} \hyperlink{ngd54084}{{[}NGD54084{]}} \hyperlink{ngl13744}{{[}NGL13744{]}} \hyperlink{ngd44607}{{[}NGD44607{]}} \hyperlink{ngd29291}{{[}NGD29291{]}} \hyperlink{ngd87831}{{[}NGD87831{]}}
\hyperlink{ngd87831}{{[}NGD87831{]}} \hyperlink{ngl3937}{{[}NGL3937{]}} \hyperlink{ngd22968}{{[}NGD22968{]}} \hyperlink{nga15246}{{[}NGA15246{]}} \hyperlink{ngd5622}{{[}NGD5622{]}} \hyperlink{ngd2547}{{[}NGD2547{]}}
\hyperlink{ngd18354}{{[}NGD18354{]}}.

Esta familia de algoritmos se adapta bien a los requerimientos principales de
\href{http://www.digitalmars.com/d/}{D} en cuanto a recolección de basura (ver \hyperlink{dgc-needs}{\emph{Características y necesidades particulares de D}}), por ejemplo
permite recolectar de forma conservativa, no impone un \emph{overhead} a menos que
se utilice el recolector, permite liberar memoria manualmente, se adapta de
forma simple para soportar punteros \emph{interiores} y permite finalizar objetos
(con las limitaciones mencionadas en \hyperlink{dgc-prob-final}{\emph{Orientación a objetos y finalización}}).

Sin embargo muchas de las limitaciones del recolector actual (ver
\hyperlink{dgc-bad}{\emph{Problemas y limitaciones}}), no son inherentes al marcado y barrido, por lo que aún
conservando la base del algoritmo, es posible realizar una cantidad de mejoras
considerable.

Una de las principales mejoras que pueden realizarse es hacer al recolector
\hyperlink{gc-concurrent}{\emph{concurrente}} y más \hyperlink{gc-conserv}{\emph{preciso}}. Estas
dos mejoras solamente alcanzarían para mejorar de forma notable el tiempo de
pausa en las recolecciones y la cantidad de memoria retenida debido a \emph{falsos
positivos}.

Más adelante veremos detalles sobre algunos de estos aspectos y sobre algunos
algoritmos particulares que permiten hacer concurrente al recolector actual.


\subsubsection{Copia de semi-espacio}

La copia de semi-espacio, al igual que cualquier otro tipo de recolector con
movimiento, requiere (en la mayoría de los casos) disponer de una
\hyperlink{gc-conserv}{\emph{precisión}} casi completa. Las celdas para las cuales hay
alguna referencia que no es precisa no pueden ser movidas, ya que al no estar
seguros que la referencia sea tal, ésta no puede ser actualizada con la
dirección de la nueva ubicación de la celda movida porque de no ser una
referencia se estarían alterando datos del usuario, corrompiéndolos.

Es por esto que si el recolector no es mayormente preciso, las celdas que
pueden ser movidas son muy pocas y, por lo tanto, se pierden las principales
ventajas de esta familia de recolectores (como la capacidad de asignar nueva
memoria mediante \emph{pointer bump allocation}).

Este aumento de precisión, sin embargo, es bastante realizable. Es posible, en
teoría, hacer que al menos el \emph{heap} sea preciso, aunque es discutible si en
la práctica es aceptable el \emph{overhead} en espacio necesario para almacenar la
información del tipo de una celda. Esto se analiza en más detalle al evaluar
la recolección precisa en la siguiente sección.

Si bien las principales herramientas para que sea viable un recolector por
copia de semi-espacio están disponibles en \href{http://www.digitalmars.com/d/}{D} (como la posibilidad de hacer
\emph{pinning} the celdas o el potencial incremento de precisión), este lenguaje
nunca va a poder proveer precisión total, haciendo que no sea posible
implementar un recolector por copia de semi-espacio puro. Siempre habrá que
disponer un esquema híbrido para poder manejar las celdas que no puedan
moverse, incrementado mucho la complejidad del recolector.

Si bien un esquema híbrido es algo técnicamente posible, nuevamente la
resistencia social a un cambio de esta envergadura es de importancia
suficiente como para inclinarse por una solución menos drástica.
\hypertarget{dgc-via-art}{}

\subsection{Principales categorías del estado del arte}

En esta sección se realiza un análisis de la viabilidad de las principales
categorías de recolectores según se presentaron en la sección \hyperlink{gc-art}{\emph{Estado del arte}}.


\subsubsection{Recolección directa / indirecta}

Como se ha visto al analizar el conteo de referencias, lo más apropiado para
\href{http://www.digitalmars.com/d/}{D} pareciera ser continuar con el esquema de recolección indirecta, de forma
tal de que el precio de la recolección solo deba ser pagado cuando el
\emph{mutator} realmente necesita del recolector. Es por esto que no parece ser una
opción viable introducir recolección directa en este trabajo.


\subsubsection{Recolección incremental}

La recolección incremental puede ser beneficiosa para \href{http://www.digitalmars.com/d/}{D}, dado que puede
servir para disminuir el tiempo de pausa del recolector. Sin embargo, en
general es necesario instrumentar el \emph{mutator} para reportar cambios en el
grafo del conectividad al recolector. Además puede contar con los mismos
problemas que la recolección directa, puede hacer que el usuario tenga que
pagar el precio de la recolección, incluso cuando no la necesita, si por cada
asignación el recolector realiza parte de una recolección que no fue
solicitada.


\subsubsection{Recolección concurrente / paralela / \emph{stop-the-world}}

El recolector actual es \emph{stop-the-world}, sin embargo esta es una de las
principales críticas que tiene. El recolector se podría ver beneficiado de
recolección paralela, tanto para realizar la recolección más velozmente en
ambientes \emph{multi-core}, como para disminuir el tiempo de pausa, un factor muy
importante para programas que necesiten tener baja latencia, como programas
\emph{real-time}.

En general los recolectores concurrentes necesitan también instrumentar el
\emph{mutator} para reportar cambios en el grafo de conectividad al recolector,
como sucede con la recolección directa o incremental, sin embargo hay
algoritmos que no tienen este requerimiento, utilizando servicios del sistema
operativo para tener una \emph{fotografía} de la memoria para que la fase de
marcado pueda realizarse sin perturbar al \emph{mutator} ni requerir de su
cooperación \hyperlink{rodr97}{{[}RODR97{]}}. Este tipo de algoritmos serían un buen candidato para
\href{http://www.digitalmars.com/d/}{D}, dado que requiere pocos cambios y es transparente al \emph{mutator}.


\subsubsection{Recolección conservativa / precisa}

Si bien \href{http://www.digitalmars.com/d/}{D} puede proveer al recolector de basura información de tipos para los
objetos almacenados en el \emph{heap}, todo recolector para \href{http://www.digitalmars.com/d/}{D} deberá soportar
cierto grado de recolección conservativa (ver \hyperlink{gc-conserv}{\emph{Recolectores conservativos versus precisos}}), debido a las
siguientes razones:
\begin{itemize}
\item {} 
Si bien \href{http://www.digitalmars.com/d/}{D} podría incorporar información de tipos para el \emph{stack}
(utilizando, por ejemplo, la técnica de \emph{shadow stack} \hyperlink{hend02}{{[}HEND02{]}}), para
poder interactuar con C/C++, el recolector debe poder interpretar los \emph{stack
frames} \footnote{
Un \emph{stack frame} (\emph{marco de la pila} en castellano),
también conocido como \emph{activation record} (o \emph{registro de activación} en
castellano) es una estructura de datos dependiente de la arquitectura que
contiene información del estado de una función, incluyendo, por ejemplo,
sus variables locales, parámetros y dirección de retorno.
} de estos lenguajes, que no disponen de información
de tipos.

\item {} 
Los registros del procesador tienen un problema similar, con la diferencia
de que el costo de implementar algo similar a \emph{shadow stack} para los
registros sería impracticable, más allá de que exista la misma limitación
que con el \emph{stack} para poder interactuar con C/C++.

\item {} 
\href{http://www.digitalmars.com/d/}{D} soporta uniones (ver \hyperlink{d-low-level}{\emph{Programación de bajo nivel (system programming)}}). Para una unión es imposible
determinar si un campo es un puntero o no. Por ejemplo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{union} \PYG{n}{U} \PYG{p}{\PYGZob{}}
   \PYG{n}{size\PYGZus{}t} \PYG{n}{x}\PYG{p}{;}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{p}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

Aquí el recolector no puede saber nunca si el valor almacenado será un
\code{size\_t} o un \code{void*}, por lo tanto deberá tratar \textbf{siempre} esa
palabra de forma conservativa (es decir, interpretarla como un \emph{posible}
puntero). Este requerimiento puede ser relajado si el usuario proveyera
alguna forma de determinar que tipo está almacenando la unión en un
determinado momento. Sin embargo el costo de pedir al usuario este tipo de
restricción puede ser muy alto.

\end{itemize}

Durante el desarrollo de este trabajo se encontra un trabajo relacionado
avanzando en este sentido, que agrega precisión al marcado del \emph{heap}. David
Simcha comienza explorando la posibilidad de agregar precisión parcial al
recolector, generando información sobre la ubicación de los punteros para cada
tipo \hyperlink{dbz3463}{{[}DBZ3463{]}}. Su trabajo se limita a una implementación a nivel biblioteca
de usuario y sobre \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0}.  Desafortunadamente su trabajo pasa desapercibido
por un buen tiempo.

Sin embargo un tiempo después Vincent Lang (mejor conocido como \emph{wm4} en la
comunidad de \href{http://www.digitalmars.com/d/}{D}), retoma este trabajo, pero modificando el compilador \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD}
y trabajando con \href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0} y \href{http://www.dsource.org/projects/tango}{Tango}. Es por esto que el aumento de precisión
parece ser un área fértil para este trabajo, en particular si se colabora con
el trabajo realizado por David y Vincent.


\subsubsection{Recolección con movimiento de celdas}

Esta posibilidad ya se ha discutido al analizar la posibilidad de utilizar
recolección con copia de semi-espacios. El trabajo mencionado en la sub-sección
anterior agrega información suficiente como poder diferenciar que celdas se
pueden mover y cuales no, sin embargo queda como incógnita qué proporción de
celdas deben permanecer inmovilizadas como para evaluar si un cambio tan
grande puede rendir frutos o no.

A priori, pareciera que la relación cantidad y complejidad de cambios sobre
beneficios potenciales no fuera muy favorable a esta mejora.


\subsubsection{Lista de libres / \emph{pointer bump allocation}}

Como consecuencia de los puntos anteriores, no es técnicamente posible
realizar \emph{pointer bump allocation} pura en \href{http://www.digitalmars.com/d/}{D}. Al haber objetos \emph{pinned},
siempre es necesario o bien contar con una lista de libres, o detectar
\emph{huecos} en un esquema de \emph{pointer bump allocation}. Es por esto que parece
ser más viable conservar el esquema de listas de libres.

Esta mejora también entra en la categoría de opciones viables pero cuya
complejidad no parece valer la pena dada la limitada utilidad que se espera
dadas las particulares características de \href{http://www.digitalmars.com/d/}{D} en cuanto a precisión de
información de tipos de \emph{stack}, uniones, etc.


\subsubsection{Recolección por particiones / generacional}

Una vez más la recolección por particiones, en particular la generacional,
requiere de la instrumentación del \emph{mutator} para comunicar cambios en el
grafo de conectividad al recolector, por lo que es poco viable. Aunque existen
algoritmos que no necesitan este tipo de comunicación dado que está
garantizado que no existan conexiones entre celdas de las distintas
particiones, requiere grandes cambios en el compilador y realizar análisis
estático bastante complejo \hyperlink{hirz03}{{[}HIRZ03{]}}. Además al ser \href{http://www.digitalmars.com/d/}{D} un lenguaje de bajo
nivel, es muy difícil garantizar que estas conexiones inter-particiones no
puedan existir realmente; y de hacerlo, podría ser demasiado restrictivo.

\resetcurrentobjects
\hypertarget{--doc-solucion}{}

\hypertarget{solucion}{}\chapter{Solución adoptada}

Como hemos visto en \hyperlink{dgc}{\emph{Recolección de basura en D}}, la mejora del recolector de basura puede ser
abordada desde múltiples flancos, con varias alternativas viables. Por lo
tanto, para reducir la cantidad de posibilidades hay que tener en cuenta uno
de los principales objetivos de este trabajo: encontrar una solución que tenga
una buena probabilidad de ser adoptada por el lenguaje, o alguno de sus
compiladores al menos. Para asegurar esto, la solución debe tener un alto
grado de aceptación en la comunidad, lo que implica algunos puntos claves:
\begin{itemize}
\item {} 
La eficiencia general de la solución no debe ser notablemente peor, en
ningún aspecto, que la implementación actual.

\item {} 
Los cambios no deben ser drásticos.

\item {} 
La solución debe atacar de forma efectiva al menos uno de los problemas
principales del recolector actual.

\end{itemize}

Bajo estos requerimientos, se concluye que probablemente el área más fértil
para explorar sea la falta de concurrencia por cumplir todos estos puntos:
\begin{itemize}
\item {} 
Si bien hay evidencia en la literatura sobre el incremento del tiempo de
ejecución total de ejecución de un programa al usar algoritmos concurrentes,
éste no es, en general, muy grande comparativamente.

\item {} 
Existen algoritmos de recolección concurrente que no requieren ningún grado
de cooperación por parte del lenguaje o el compilador.

\item {} 
La falta de concurrencia y los largos tiempos de pausa es una de las
críticas más frecuentes al recolector actual por parte de la comunidad.

\end{itemize}

A pesar de ser la concurrencia la veta principal a explorar en este trabajo,
se intenta abordar los demás problemas planteados siempre que sea posible
hacerlo sin alejarse demasiado del objetivo principal.


\hypertarget{sol-bench}{}\section{Banco de pruebas}

Teniendo en cuenta que uno de los objetivos principales es no empeorar la
eficiencia general de forma notable, la confección de un banco de pruebas es
un aspecto fundamental, para poder comprobar con cada cambio que la eficiencia
final no se vea notablemente afectada.

La confección de un banco de pruebas no es una tarea trivial, mucho menos para
un lenguaje con el nivel de fragmentación que tuvo \href{http://www.digitalmars.com/d/}{D} (que hace que a fines
prácticos hayan 3 versiones del lenguaje compitiendo), y cuya masa crítica de
usuarios es de aficionados que usualmente abandonan los proyectos, quedando
obsoletos rápidamente.

Con el objetivo de confeccionar este banco de pruebas, desde el comienzo del
trabajo se han recolectado (usando como fuente principalmente el grupo de
noticias de \href{http://www.digitalmars.com/d/}{D} \footnote{
Cabe destacar que en general todos los programas recolectados
han sido modificados levemente para ajustarlos mejor a las necesidades del
banco de prueba (entre las modificaciones más frecuentes se encuentran la
conversión de \href{http://www.dsource.org/projects/phobos}{Phobos} a \href{http://www.dsource.org/projects/tango}{Tango} y la eliminación de mensajes por salida
estándar).
}) programas triviales sintetizados con el único
propósito de mostrar problemas con el recolector de basura. Otros programas de
este estilo fueron escritos explícitamente para este trabajo.

Además se han recolectado algunos pequeños programas portados de otros
lenguajes de programación, que si bien son pequeños y tienen como objetivo
ejercitar el recolector de basura, son programas reales que resuelven un
problema concreto, lo que otorga un juego de pruebas un poco más amplio que
los programas triviales.

Pero probablemente lo más importante para confeccionar un banco de pruebas
verdaderamente útil es disponer de programas reales, que hayan sido diseñados
con el único objetivo de hacer su trabajo, sin pensar en como impacta el
recolector sobre ellos (ni ellos sobre el recolector). Estos programas proveen
las pruebas más realistas y amplias. Desgraciadamente no hay muchos programas
reales escritos en \href{http://www.digitalmars.com/d/}{D} disponibles públicamente, y no se encontró en la
comunidad tampoco una muestra de voluntad por compartir programas privados
para usar como banco de pruebas en este trabajo.

Por lo tanto el banco de pruebas que se conformó como una mezcla de estas tres
grandes categorías.


\hypertarget{sol-bench-synth}{}\subsection{Pruebas sintetizadas}

Este es el juego de programas triviales, escritos con el único objetivo de
ejercitar un área particular y acotada del recolector.


\subsubsection{\texttt{bigarr}}

Su objetivo es ejercitar la manipulación de arreglos de tamaño considerable
que almacenan objetos de tamaño pequeño o mediano. Esta prueba fue \href{http://www.digitalmars.com/webnews/newsgroups.php?art\_group=digitalmars.D\&article\_id=54084}{hallada}
en el grupo de noticias de \href{http://www.digitalmars.com/d/}{D} y escrita por Babele Dunnit y aunque
originalmente fue concebido para mostrar un problema con la concatenación de
arreglos (como se aprecia en la sentencia \code{version(loseMemory)}), ejercita
los aspectos más utilizados del del recolector: manipulación de arreglos
y petición e memoria. Es una de las pruebas que más estresa al recolector ya
que todo el trabajo que realiza el programa es utilizar sus servicios.

Código fuente:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{const} \PYG{n}{IT} \PYG{p}{=} \PYG{l+m+mi}{300}\PYG{p}{;}
\PYG{k}{const} \PYG{n}{N1} \PYG{p}{=} \PYG{l+m+mi}{20\PYGZus{}000}\PYG{p}{;}
\PYG{k}{const} \PYG{n}{N2} \PYG{p}{=} \PYG{l+m+mi}{40\PYGZus{}000}\PYG{p}{;}

\PYG{k}{class} \PYG{n}{Individual}
\PYG{p}{\PYGZob{}}
   \PYG{n}{Individual}\PYG{p}{[}\PYG{l+m+mi}{20}\PYG{p}{]} \PYG{n}{children}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k}{class} \PYG{n}{Population}
\PYG{p}{\PYGZob{}}
   \PYG{k+kt}{void} \PYG{n}{grow}\PYG{p}{(}\PYG{p}{)}
   \PYG{p}{\PYGZob{}}
      \PYG{k}{foreach} \PYG{p}{(}\PYG{k}{inout} \PYG{n}{individual}\PYG{p}{;} \PYG{n}{individuals}\PYG{p}{)}
         \PYG{n}{individual} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Individual}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
   \PYG{n}{Individual}\PYG{p}{[}\PYG{n}{N1}\PYG{p}{]} \PYG{n}{individuals}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k}{version} \PYG{p}{=} \PYG{n}{loseMemory}\PYG{p}{;}

\PYG{k+kt}{int} \PYG{n}{main}\PYG{p}{(}\PYG{k+kt}{char}\PYG{p}{[}\PYG{p}{]}\PYG{p}{[}\PYG{p}{]} \PYG{n}{args}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{n}{Population} \PYG{n}{testPop1} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Population}\PYG{p}{;}
   \PYG{n}{Population} \PYG{n}{testPop2} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Population}\PYG{p}{;}
   \PYG{n}{Individual}\PYG{p}{[}\PYG{n}{N2}\PYG{p}{]} \PYG{n}{indi}\PYG{p}{;}
   \PYG{k}{for} \PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{n}{i} \PYG{p}{\textless{}} \PYG{n}{IT}\PYG{p}{;} \PYG{n}{i}\PYG{p}{++}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{n}{testPop1}\PYG{p}{.}\PYG{n}{grow}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
      \PYG{n}{testPop2}\PYG{p}{.}\PYG{n}{grow}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
      \PYG{k}{version} \PYG{p}{(}\PYG{n}{loseMemory}\PYG{p}{)} \PYG{p}{\PYGZob{}}
         \PYG{n}{indi}\PYG{p}{[}\PYG{p}{]} \PYG{p}{=} \PYG{n}{testPop1}\PYG{p}{.}\PYG{n}{individuals} \PYG{p}{\textasciitilde{}} \PYG{n}{testPop2}\PYG{p}{.}\PYG{n}{individuals}\PYG{p}{;}
      \PYG{p}{\PYGZcb{}}
      \PYG{k}{version} \PYG{p}{(}\PYG{n}{everythingOk}\PYG{p}{)} \PYG{p}{\PYGZob{}}
         \PYG{n}{indi}\PYG{p}{[}\PYG{l+m+mi}{0} \PYG{p}{..} \PYG{n}{N1}\PYG{p}{]} \PYG{p}{=} \PYG{n}{testPop1}\PYG{p}{.}\PYG{n}{individuals}\PYG{p}{;}
         \PYG{n}{indi}\PYG{p}{[}\PYG{n}{N1} \PYG{p}{..} \PYG{n}{N2}\PYG{p}{]} \PYG{p}{=} \PYG{n}{testPop2}\PYG{p}{.}\PYG{n}{individuals}\PYG{p}{;}
      \PYG{p}{\PYGZcb{}}
   \PYG{p}{\PYGZcb{}}
   \PYG{k}{return} \PYG{l+m+mi}{0}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}


\subsubsection{\texttt{concpu} y \texttt{conalloc}}

Estos dos programas fueron escritos especialmente para este trabajo con el fin
de ejercitar la interacción entre el recolector y un \emph{mutator} con varios
hilos. La única diferencia entre ellos es que \code{concpu} lanza hilos que hacen
trabajar de forma intensiva el procesador pero que no utilizan servicios del
recolector, salvo en el hilo principal, mientras que \code{conalloc} utiliza
servicios del recolector en todos los hilos lanzados.

El objetivo de estos programas es medir el impacto de las pausas del
recolector. Se espera medir dos tipos de pausa principales, por un lado el
tiempo máximo de pausa real, que puede involucrar a más de un hilo y por otro
el tiempo de \emph{stop-the-world}, es decir, el tiempo en que los hilos son
efectivamente pausados por el recolector para realizar una tarea que necesite
trabajar con una versión estática de la memoria del programa.

Se espera \code{concpu} sea capaz de explotar cualquier reducción en el tiempo de
\emph{stop-the-world}, ya que los hilos solo son interrumpidos por este tipo de
pausa. Por otro lado, se espera que \code{conalloc} sea afectado por el tiempo
máximo de pausa, que podrían sufrir los hilos incluso cuando el \emph{mundo} sigue
su marcha, debido al \emph{lock} global del recolector y que los hilos usan
servicios de éste.

Código fuente de \code{concpu}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{core}\PYG{p}{.}\PYG{n}{Thread}\PYG{p}{:} \PYG{n}{Thread}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{core}\PYG{p}{.}\PYG{n}{Atomic}\PYG{p}{:} \PYG{n}{Atomic}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{io}\PYG{p}{.}\PYG{n}{device}\PYG{p}{.}\PYG{n}{File}\PYG{p}{:} \PYG{n}{File}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{util}\PYG{p}{.}\PYG{n}{digest}\PYG{p}{.}\PYG{n}{Sha512}\PYG{p}{:} \PYG{n}{Sha512}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{util}\PYG{p}{.}\PYG{n}{Convert}\PYG{p}{:} \PYG{n}{to}\PYG{p}{;}

\PYG{k}{auto} \PYG{n}{N} \PYG{p}{=} \PYG{l+m+mi}{100}\PYG{p}{;}
\PYG{k}{auto} \PYG{n}{NT} \PYG{p}{=} \PYG{l+m+mi}{2}\PYG{p}{;}
\PYG{k+kt}{ubyte}\PYG{p}{[}\PYG{p}{]} \PYG{n}{BYTES}\PYG{p}{;}
\PYG{n}{Atomic}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{)} \PYG{n}{running}\PYG{p}{;}

\PYG{k+kt}{void} \PYG{n}{main}\PYG{p}{(}\PYG{k+kt}{char}\PYG{p}{[}\PYG{p}{]}\PYG{p}{[}\PYG{p}{]} \PYG{n}{args}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{k}{auto} \PYG{n}{fname} \PYG{p}{=} \PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}\PYG{p}{;}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{args}\PYG{p}{.}\PYG{n}{length} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{3}\PYG{p}{)}
      \PYG{n}{fname} \PYG{p}{=} \PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{3}\PYG{p}{]}\PYG{p}{;}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{args}\PYG{p}{.}\PYG{n}{length} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{2}\PYG{p}{)}
      \PYG{n}{NT} \PYG{p}{=} \PYG{n}{to}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{)}\PYG{p}{(}\PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{2}\PYG{p}{]}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{args}\PYG{p}{.}\PYG{n}{length} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{1}\PYG{p}{)}
      \PYG{n}{N} \PYG{p}{=} \PYG{n}{to}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{)}\PYG{p}{(}\PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{1}\PYG{p}{]}\PYG{p}{)}\PYG{p}{;}
   \PYG{n}{N} \PYG{p}{/=} \PYG{n}{NT}\PYG{p}{;}
   \PYG{n}{running}\PYG{p}{.}\PYG{n}{store}\PYG{p}{(}\PYG{n}{NT}\PYG{p}{)}\PYG{p}{;}
   \PYG{n}{BYTES} \PYG{p}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{k+kt}{ubyte}\PYG{p}{[}\PYG{p}{]}\PYG{p}{)} \PYG{n}{File}\PYG{p}{.}\PYG{n}{get}\PYG{p}{(}\PYG{n}{fname}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{auto} \PYG{n}{threads} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Thread}\PYG{p}{[}\PYG{n}{NT}\PYG{p}{]}\PYG{p}{;}
   \PYG{k}{foreach}\PYG{p}{(}\PYG{k}{ref} \PYG{n}{thread}\PYG{p}{;} \PYG{n}{threads}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{n}{thread} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Thread}\PYG{p}{(}\PYG{p}{\&}\PYG{n}{doSha}\PYG{p}{)}\PYG{p}{;}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n}{start}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
   \PYG{k}{while} \PYG{p}{(}\PYG{n}{running}\PYG{p}{.}\PYG{n}{load}\PYG{p}{(}\PYG{p}{)}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{k}{auto} \PYG{n}{a} \PYG{p}{=} \PYG{k}{new} \PYG{k+kt}{void}\PYG{p}{[}\PYG{p}{]}\PYG{p}{(}\PYG{n}{BYTES}\PYG{p}{.}\PYG{n}{length} \PYG{p}{/} \PYG{l+m+mi}{4}\PYG{p}{)}\PYG{p}{;}
      \PYG{n}{a}\PYG{p}{[}\PYG{p}{]} \PYG{p}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{k+kt}{void}\PYG{p}{[}\PYG{p}{]}\PYG{p}{)} \PYG{n}{BYTES}\PYG{p}{[}\PYG{p}{]}\PYG{p}{;}
      \PYG{n}{Thread}\PYG{p}{.}\PYG{n}{yield}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
   \PYG{k}{foreach}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{;} \PYG{n}{threads}\PYG{p}{)}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n}{join}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k+kt}{void} \PYG{n}{doSha}\PYG{p}{(}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{k}{auto} \PYG{n}{sha} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Sha512}\PYG{p}{;}
   \PYG{k}{for} \PYG{p}{(}\PYG{n}{size\PYGZus{}t} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{n}{i} \PYG{p}{\textless{}} \PYG{n}{N}\PYG{p}{;} \PYG{n}{i}\PYG{p}{++}\PYG{p}{)}
      \PYG{n}{sha}\PYG{p}{.}\PYG{n}{update}\PYG{p}{(}\PYG{n}{BYTES}\PYG{p}{)}\PYG{p}{;}
   \PYG{n}{running}\PYG{p}{.}\PYG{n}{decrement}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

El código de \code{conalloc} es igual excepto por la función \code{doSha()}, que es
de la siguiente manera:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k+kt}{void} \PYG{n}{doSha}\PYG{p}{(}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{k}{for} \PYG{p}{(}\PYG{n}{size\PYGZus{}t} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{n}{i} \PYG{p}{\textless{}} \PYG{n}{N}\PYG{p}{;} \PYG{n}{i}\PYG{p}{++}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{k}{auto} \PYG{n}{sha} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Sha512}\PYG{p}{;}
      \PYG{n}{sha}\PYG{p}{.}\PYG{n}{update}\PYG{p}{(}\PYG{n}{BYTES}\PYG{p}{)}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
   \PYG{n}{running}\PYG{p}{.}\PYG{n}{decrement}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}


\subsubsection{\texttt{mcore}}

Escrito por David Schima y también \href{http://www.digitalmars.com/webnews/newsgroups.php?art\_group=digitalmars.D\&article\_id=103563}{hallado} en el grupo de noticias de \href{http://www.digitalmars.com/d/}{D},
este programa pretende mostrar como afecta el \emph{lock} global del recolector
en ambientes \emph{multi-core}, incluso cuando a simple vista parecen no utilizarse
servicios del recolector:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{core}\PYG{p}{.}\PYG{n}{Thread}\PYG{p}{;}

\PYG{k+kt}{void} \PYG{n}{main}\PYG{p}{(}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{k}{enum} \PYG{p}{\PYGZob{}} \PYG{n}{nThreads} \PYG{p}{=} \PYG{l+m+mi}{4} \PYG{p}{\PYGZcb{}}\PYG{p}{;}
   \PYG{k}{auto} \PYG{n}{threads} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Thread}\PYG{p}{[}\PYG{n}{nThreads}\PYG{p}{]}\PYG{p}{;}
   \PYG{k}{foreach} \PYG{p}{(}\PYG{k}{ref} \PYG{n}{thread}\PYG{p}{;} \PYG{n}{threads}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{n}{thread} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Thread}\PYG{p}{(}\PYG{p}{\&}\PYG{n}{doAppending}\PYG{p}{)}\PYG{p}{;}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n}{start}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
   \PYG{k}{foreach} \PYG{p}{(}\PYG{n}{thread}\PYG{p}{;} \PYG{n}{threads}\PYG{p}{)}
      \PYG{n}{thread}\PYG{p}{.}\PYG{n}{join}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k+kt}{void} \PYG{n}{doAppending}\PYG{p}{(}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{k+kt}{uint}\PYG{p}{[}\PYG{p}{]} \PYG{n}{arr}\PYG{p}{;}
   \PYG{k}{for} \PYG{p}{(}\PYG{n}{size\PYGZus{}t} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{n}{i} \PYG{p}{\textless{}} \PYG{l+m+mi}{1\PYGZus{}000\PYGZus{}000}\PYG{p}{;} \PYG{n}{i}\PYG{p}{++}\PYG{p}{)}
      \PYG{n}{arr} \PYG{p}{\textasciitilde{}=} \PYG{n}{i}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

El secreto está en que la concatenación de arreglos utiliza por detrás
servicios del recolector, por lo tanto un programa multi-hilo en el cual los
hilos (aparentemente) no comparten ningún estado, se puede ver
considerablemente afectado por el recolector (siendo este efecto más visible
en ambientes \emph{multi-core} por el nivel de sincronización extra que significa
a nivel de \emph{hardware}). Cabe destacar, sin embargo, que en \href{http://www.kernel.org/}{Linux} el efecto no
es tan notorio comparado al reporte de David Schima.


\subsubsection{\texttt{split}}

Este programa trivial lee un archivo de texto y genera un arreglo de cadenas
de texto resultantes de partir el texto en palabras. Fue escrito por Leonardo
Maffi y también \href{http://www.digitalmars.com/webnews/newsgroups.php?art\_group=digitalmars.D\&article\_id=67673}{hallado} en el grupo de noticias de \href{http://www.digitalmars.com/d/}{D}. Su objetivo era
mostrar lo ineficiente que puede ser concatenar datos a un mismo arreglo
repetidas veces y ha desembocado en una pequeña optimización que sirvió para
paliar el problema de forma razonablemente efectiva \hyperlink{pan09}{{[}PAN09{]}}.

Código fuente:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{io}\PYG{p}{.}\PYG{n}{device}\PYG{p}{.}\PYG{n}{File}\PYG{p}{:} \PYG{n}{File}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{text}\PYG{p}{.}\PYG{n}{Util}\PYG{p}{:} \PYG{n}{delimit}\PYG{p}{;}
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{util}\PYG{p}{.}\PYG{n}{Convert}\PYG{p}{:} \PYG{n}{to}\PYG{p}{;}

\PYG{k+kt}{int} \PYG{n}{main}\PYG{p}{(}\PYG{k+kt}{char}\PYG{p}{[}\PYG{p}{]}\PYG{p}{[}\PYG{p}{]} \PYG{n}{args}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{args}\PYG{p}{.}\PYG{n}{length} \PYG{p}{\textless{}} \PYG{l+m+mi}{2}\PYG{p}{)}
      \PYG{k}{return} \PYG{l+m+mi}{1}\PYG{p}{;}
   \PYG{k}{auto} \PYG{n}{txt} \PYG{p}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{k+kt}{byte}\PYG{p}{[}\PYG{p}{]}\PYG{p}{)} \PYG{n}{File}\PYG{p}{.}\PYG{n}{get}\PYG{p}{(}\PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{1}\PYG{p}{]}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{auto} \PYG{n}{n} \PYG{p}{=} \PYG{p}{(}\PYG{n}{args}\PYG{p}{.}\PYG{n}{length} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{2}\PYG{p}{)} \PYG{p}{?} \PYG{n}{to}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{uint}\PYG{p}{)}\PYG{p}{(}\PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{2}\PYG{p}{]}\PYG{p}{)} \PYG{p}{:} \PYG{l+m+mi}{1}\PYG{p}{;}
   \PYG{k}{if} \PYG{p}{(}\PYG{n}{n} \PYG{p}{\textless{}} \PYG{l+m+mi}{1}\PYG{p}{)}
      \PYG{n}{n} \PYG{p}{=} \PYG{l+m+mi}{1}\PYG{p}{;}
   \PYG{k}{while} \PYG{p}{(}\PYG{p}{--}\PYG{n}{n}\PYG{p}{)}
      \PYG{n}{txt} \PYG{p}{\textasciitilde{}=} \PYG{n}{txt}\PYG{p}{;}
   \PYG{k}{auto} \PYG{n}{words} \PYG{p}{=} \PYG{n}{delimit}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{byte}\PYG{p}{)}\PYG{p}{(}\PYG{n}{txt}\PYG{p}{,} \PYG{k}{cast}\PYG{p}{(}\PYG{k+kt}{byte}\PYG{p}{[}\PYG{p}{]}\PYG{p}{)} \PYG{l+s}{" \PYGZbs{}t\PYGZbs{}n\PYGZbs{}r"}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{return} \PYG{p}{!}\PYG{n}{words}\PYG{p}{.}\PYG{n}{length}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}


\subsubsection{\texttt{rnddata}}

Este programa fue escrito por Oskar Linde y nuevamente \href{http://www.digitalmars.com/webnews/newsgroups.php?art\_group=digitalmars.D\&article\_id=46407}{hallado} en el grupo
de noticias. Fue construido para mostrar como el hecho de que el recolector
sea conservativo puede hacer que al leer datos binarios hayan muchos \emph{falsos
positivos} que mantengan vivas celdas que en realidad ya no deberían ser
accesibles desde el \emph{root set} del grafo de conectividad.

Código fuente:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{math}\PYG{p}{.}\PYG{n}{random}\PYG{p}{.}\PYG{n}{Random}\PYG{p}{;}

\PYG{k}{const} \PYG{n}{IT} \PYG{p}{=} \PYG{l+m+mi}{125}\PYG{p}{;} \PYG{c+c1}{// number of iterations, each creates an object}
\PYG{k}{const} \PYG{n}{BYTES} \PYG{p}{=} \PYG{l+m+mi}{1\PYGZus{}000\PYGZus{}000}\PYG{p}{;} \PYG{c+c1}{// \textasciitilde{}1MiB per object}
\PYG{k}{const} \PYG{n}{N} \PYG{p}{=} \PYG{l+m+mi}{50}\PYG{p}{;} \PYG{c+c1}{// \textasciitilde{}50MiB of initial objects}

\PYG{k}{class} \PYG{n}{C}
\PYG{p}{\PYGZob{}}
   \PYG{n}{C} \PYG{n}{c}\PYG{p}{;} \PYG{c+c1}{// makes the compiler not set NO\PYGZus{}SCAN}
   \PYG{k+kt}{long}\PYG{p}{[}\PYG{n}{BYTES}\PYG{p}{/}\PYG{k+kt}{long}\PYG{p}{.}\PYG{n}{sizeof}\PYG{p}{]} \PYG{n}{data}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k+kt}{void} \PYG{n}{main}\PYG{p}{(}\PYG{p}{)} \PYG{p}{\PYGZob{}}
   \PYG{k}{auto} \PYG{n}{rand} \PYG{p}{=} \PYG{k}{new} \PYG{n}{Random}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
   \PYG{n}{C}\PYG{p}{[}\PYG{p}{]} \PYG{n}{objs}\PYG{p}{;}
         \PYG{n}{objs}\PYG{p}{.}\PYG{n}{length} \PYG{p}{=} \PYG{n}{N}\PYG{p}{;}
   \PYG{k}{foreach} \PYG{p}{(}\PYG{k}{ref} \PYG{n}{o}\PYG{p}{;} \PYG{n}{objs}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{n}{o} \PYG{p}{=} \PYG{k}{new} \PYG{n}{C}\PYG{p}{;}
      \PYG{k}{foreach} \PYG{p}{(}\PYG{k}{ref} \PYG{n}{x}\PYG{p}{;} \PYG{n}{o}\PYG{p}{.}\PYG{n}{data}\PYG{p}{)}
         \PYG{n}{rand}\PYG{p}{(}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
   \PYG{k}{for} \PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;} \PYG{n}{i} \PYG{p}{\textless{}} \PYG{n}{IT}\PYG{p}{;} \PYG{p}{++}\PYG{n}{i}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{n}{C} \PYG{n}{o} \PYG{p}{=} \PYG{k}{new} \PYG{n}{C}\PYG{p}{;}
      \PYG{k}{foreach} \PYG{p}{(}\PYG{k}{ref} \PYG{n}{x}\PYG{p}{;} \PYG{n}{o}\PYG{p}{.}\PYG{n}{data}\PYG{p}{)}
         \PYG{n}{rand}\PYG{p}{(}\PYG{n}{x}\PYG{p}{)}\PYG{p}{;}
      \PYG{c+c1}{// do something with the data...}
   \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}


\subsubsection{\texttt{sbtree}}

Este programa está basado en la prueba de nombre \code{binary-trees} de \href{http://shootout.alioth.debian.org/}{The
Computer Language Benchmarks Game}, una colección de 12 programas escritos
en alrededor de 30 lenguajes de programación para comparar su eficiencia
(medida en tiempo de ejecución, uso de memoria y cantidad de líneas de código)
\hyperlink{sho10}{{[}SHO10{]}}. De este juego de programas se utilizó solo \code{binary-trees} por ser
el único destinado a ejercitar el manejo de memoria. El programa sólo manipula
árboles binarios, creándolos y recorriéndolos inmediatamente (no realiza
ningún trabajo útil). La traducción a \href{http://www.digitalmars.com/d/}{D} fue realizada por Andrey Khropov
y fue \href{http://www.digitalmars.com/webnews/newsgroups.php?art\_group=digitalmars.D\&article\_id=43991}{hallada} en el grupo de noticias.

Código fuente:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{import} \PYG{n}{tango}\PYG{p}{.}\PYG{n}{util}\PYG{p}{.}\PYG{n}{Convert}\PYG{p}{;}
\PYG{k}{alias} \PYG{k+kt}{char}\PYG{p}{[}\PYG{p}{]} \PYG{n+nb}{string}\PYG{p}{;}

\PYG{k+kt}{int} \PYG{n}{main}\PYG{p}{(}\PYG{n+nb}{string}\PYG{p}{[}\PYG{p}{]} \PYG{n}{args}\PYG{p}{)}
\PYG{p}{\PYGZob{}}
   \PYG{k+kt}{int} \PYG{n}{N} \PYG{p}{=} \PYG{n}{args}\PYG{p}{.}\PYG{n}{length} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{1} \PYG{p}{?} \PYG{n}{to}\PYG{p}{!}\PYG{p}{(}\PYG{k+kt}{int}\PYG{p}{)}\PYG{p}{(}\PYG{n}{args}\PYG{p}{[}\PYG{l+m+mi}{1}\PYG{p}{]}\PYG{p}{)} \PYG{p}{:} \PYG{l+m+mi}{1}\PYG{p}{;}
   \PYG{k+kt}{int} \PYG{n}{minDepth} \PYG{p}{=} \PYG{l+m+mi}{4}\PYG{p}{;}
   \PYG{k+kt}{int} \PYG{n}{maxDepth} \PYG{p}{=} \PYG{p}{(}\PYG{n}{minDepth} \PYG{p}{+} \PYG{l+m+mi}{2}\PYG{p}{)} \PYG{p}{\textgreater{}} \PYG{n}{N} \PYG{p}{?} \PYG{n}{minDepth} \PYG{p}{+} \PYG{l+m+mi}{2} \PYG{p}{:} \PYG{n}{N}\PYG{p}{;}
   \PYG{k+kt}{int} \PYG{n}{stretchDepth} \PYG{p}{=} \PYG{n}{maxDepth} \PYG{p}{+} \PYG{l+m+mi}{1}\PYG{p}{;}
   \PYG{k+kt}{int} \PYG{n}{check} \PYG{p}{=} \PYG{n}{TreeNode}\PYG{p}{.}\PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{l+m+mi}{0}\PYG{p}{,} \PYG{n}{stretchDepth}\PYG{p}{)}\PYG{p}{.}\PYG{n}{ItemCheck}\PYG{p}{;}
   \PYG{n}{TreeNode} \PYG{n}{longLivedTree} \PYG{p}{=} \PYG{n}{TreeNode}\PYG{p}{.}\PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{l+m+mi}{0}\PYG{p}{,} \PYG{n}{maxDepth}\PYG{p}{)}\PYG{p}{;}
   \PYG{k}{for} \PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{depth} \PYG{p}{=} \PYG{n}{minDepth}\PYG{p}{;} \PYG{n}{depth} \PYG{p}{\textless{}=} \PYG{n}{maxDepth}\PYG{p}{;} \PYG{n}{depth} \PYG{p}{+=} \PYG{l+m+mi}{2}\PYG{p}{)} \PYG{p}{\PYGZob{}}
      \PYG{k+kt}{int} \PYG{n}{iterations} \PYG{p}{=} \PYG{l+m+mi}{1} \PYG{p}{\textless{}\textless{}} \PYG{p}{(}\PYG{n}{maxDepth} \PYG{p}{-} \PYG{n}{depth} \PYG{p}{+} \PYG{n}{minDepth}\PYG{p}{)}\PYG{p}{;}
      \PYG{n}{check} \PYG{p}{=} \PYG{l+m+mi}{0}\PYG{p}{;}
      \PYG{k}{for} \PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{i} \PYG{p}{=} \PYG{l+m+mi}{1}\PYG{p}{;} \PYG{n}{i} \PYG{p}{\textless{}=} \PYG{n}{iterations}\PYG{p}{;} \PYG{n}{i}\PYG{p}{++}\PYG{p}{)} \PYG{p}{\PYGZob{}}
         \PYG{n}{check} \PYG{p}{+=} \PYG{n}{TreeNode}\PYG{p}{.}\PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{n}{i}\PYG{p}{,} \PYG{n}{depth}\PYG{p}{)}\PYG{p}{.}\PYG{n}{ItemCheck}\PYG{p}{;}
         \PYG{n}{check} \PYG{p}{+=} \PYG{n}{TreeNode}\PYG{p}{.}\PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{p}{-}\PYG{n}{i}\PYG{p}{,} \PYG{n}{depth}\PYG{p}{)}\PYG{p}{.}\PYG{n}{ItemCheck}\PYG{p}{;}
      \PYG{p}{\PYGZcb{}}
   \PYG{p}{\PYGZcb{}}
   \PYG{k}{return} \PYG{l+m+mi}{0}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k}{class} \PYG{n}{TreeNode}
\PYG{p}{\PYGZob{}}
   \PYG{n}{TreeNode} \PYG{n}{left}\PYG{p}{,} \PYG{n}{right}\PYG{p}{;}
   \PYG{k+kt}{int} \PYG{n}{item}\PYG{p}{;}

   \PYG{k}{this}\PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{item}\PYG{p}{,} \PYG{n}{TreeNode} \PYG{n}{left} \PYG{p}{=} \PYG{k+kc}{null}\PYG{p}{,} \PYG{n}{TreeNode} \PYG{n}{right} \PYG{p}{=} \PYG{k+kc}{null}\PYG{p}{)}
   \PYG{p}{\PYGZob{}}
      \PYG{k}{this}\PYG{p}{.}\PYG{n}{item} \PYG{p}{=} \PYG{n}{item}\PYG{p}{;}
      \PYG{k}{this}\PYG{p}{.}\PYG{n}{left} \PYG{p}{=} \PYG{n}{left}\PYG{p}{;}
      \PYG{k}{this}\PYG{p}{.}\PYG{n}{right} \PYG{p}{=} \PYG{n}{right}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}

   \PYG{k}{static} \PYG{n}{TreeNode} \PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{k+kt}{int} \PYG{n}{item}\PYG{p}{,} \PYG{k+kt}{int} \PYG{n}{depth}\PYG{p}{)}
   \PYG{p}{\PYGZob{}}
      \PYG{k}{if} \PYG{p}{(}\PYG{n}{depth} \PYG{p}{\textgreater{}} \PYG{l+m+mi}{0}\PYG{p}{)}
         \PYG{k}{return} \PYG{k}{new} \PYG{n}{TreeNode}\PYG{p}{(}\PYG{n}{item}\PYG{p}{,}
               \PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{l+m+mi}{2} \PYG{p}{*} \PYG{n}{item} \PYG{p}{-} \PYG{l+m+mi}{1}\PYG{p}{,} \PYG{n}{depth} \PYG{p}{-} \PYG{l+m+mi}{1}\PYG{p}{)}\PYG{p}{,}
               \PYG{n}{BottomUpTree}\PYG{p}{(}\PYG{l+m+mi}{2} \PYG{p}{*} \PYG{n}{item}\PYG{p}{,} \PYG{n}{depth} \PYG{p}{-} \PYG{l+m+mi}{1}\PYG{p}{)}\PYG{p}{)}\PYG{p}{;}
      \PYG{k}{return} \PYG{k}{new} \PYG{n}{TreeNode}\PYG{p}{(}\PYG{n}{item}\PYG{p}{)}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}

   \PYG{k+kt}{int} \PYG{n}{ItemCheck}\PYG{p}{(}\PYG{p}{)}
   \PYG{p}{\PYGZob{}}
      \PYG{k}{if} \PYG{p}{(}\PYG{n}{left}\PYG{p}{)}
         \PYG{k}{return} \PYG{n}{item} \PYG{p}{+} \PYG{n}{left}\PYG{p}{.}\PYG{n}{ItemCheck}\PYG{p}{(}\PYG{p}{)} \PYG{p}{-} \PYG{n}{right}\PYG{p}{.}\PYG{n}{ItemCheck}\PYG{p}{(}\PYG{p}{)}\PYG{p}{;}
      \PYG{k}{return} \PYG{n}{item}\PYG{p}{;}
   \PYG{p}{\PYGZcb{}}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}
\hypertarget{sol-bench-small}{}

\subsection{Programas pequeños}

Todos los pequeños programas utilizados como parte del banco de prueba
provienen del \href{http://www.irisa.fr/caps/people/truong/M2COct99/Benchmarks/Olden/Welcome.html}{Olden Benchmark} \hyperlink{car95}{{[}CAR95{]}}. Estos programas fueron diseñados
para probar el lenguaje de programación \href{http://www.martincarlisle.com/olden.html}{Olden}; un lenguaje diseñado para
paralelizar programas automáticamente en arquitecturas con memoria
distribuida. Son programas relativamente pequeños (entre 400 y 1000 líneas de
código fuente cada uno) que realizan una tarea secuencial que asigna
estructuras de datos dinámicamente. Las estructuras están usualmente
organizadas como listas o árboles, y muy raramente como arreglos. Los
programas pasan la mayor parte del tiempo solicitando memoria para almacenar
datos y el resto usando los datos almacenados, por lo que en general están
acotados en tiempo por el uso de memoria (y no de procesador).

La traducción a \href{http://www.digitalmars.com/d/}{D} fue realizada por Leonardo Maffi y están basadas a su vez
en la traducción de este juego de pruebas a \href{http://www.java.com/}{Java}, \href{http://www-ali.cs.umass.edu/DaCapo/benchmarks.html}{JOlden} \hyperlink{cmk01}{{[}CMK01{]}}. En \href{http://www.java.com/}{Java}
no se recomienda utilizar este conjunto de pruebas para medir la eficiencia
del recolector de basura, dado que se han creado mejores pruebas para este
propósito, como \href{http://www.dacapobench.org/}{DaCapo} \hyperlink{bla06}{{[}BLA06{]}}, sin embargo, dada la falta de programas
disponibles en general, y de un conjunto de pruebas especialmente diseñado
para evaluar el recolector de basura en \href{http://www.digitalmars.com/d/}{D}, se decide utilizarlas en este
trabajo de todos modos. Sin embargo sus resultados deben ser interpretados con
una pizca de suspicacia por lo mencionado anteriormente.

En general (salvo para el programa \code{voronoï}) está disponible el código
fuente portado a \href{http://www.digitalmars.com/d/}{D}, \href{http://www.java.com/}{Java} y \href{http://www.python.org/}{Python}, e incluso varias versiones con distintas
optimizaciones para reducir el consumo de tiempo y memoria. Además provee
comparaciones de tiempo entre todas ellas. Los programas utilizados en este
banco de pruebas son la versión traducida más literalmente de \href{http://www.java.com/}{Java} a \href{http://www.digitalmars.com/d/}{D}, ya
que hace un uso más intensivo del recolector que las otras versiones.

A continuación se da una pequeña descripción de cada uno de los 5 programas
traducidos y los enlaces en donde encontrar el código fuente (y las
comparaciones de tiempos estar disponibles).


\subsubsection{\texttt{bh}}

Este programa computa las interacciones gravitatorias entre un número
$N$ de cuerpos en tiempo $O(N log N)$ y está basado en árboles
heterogéneos de 8 ramas, según el algoritmo descripto por Barnes \& Hut
\hyperlink{bh86}{{[}BH86{]}}.

Código fuente disponible en:
\href{http://www.fantascienza.net/leonardo/js/dolden\_bh.zip}{http://www.fantascienza.net/leonardo/js/dolden\_bh.zip}


\subsubsection{\texttt{bisort}}

Este programa ordena $N$ números, donde $N$ es una potencia de 2,
usando un ordenamiento \emph{Bitonic} adaptativo, un algoritmo paralelo óptimo para
computadoras con memoria compartida, según describen Bilardi \& Nicolau
\hyperlink{bn98}{{[}BN98{]}}. Utiliza árboles binarios como principal estructuras de datos.

Código fuente disponible en:
\href{http://www.fantascienza.net/leonardo/js/dolden\_bisort.zip}{http://www.fantascienza.net/leonardo/js/dolden\_bisort.zip}


\subsubsection{\texttt{em3d}}

Este programa modela la propagación de ondas electromagnéticas a través de
objetos en 3 dimensiones. Realiza un cálculo simple sobre un grafo irregular
bipartito (implementado utilizando listas simplemente enlazadas) cuyos nodos
representan valores de campo eléctrico y magnético. El algoritmo es el
descripto por Culler, et al. \hyperlink{cdg93}{{[}CDG93{]}}.

Código fuente disponible en:
\href{http://www.fantascienza.net/leonardo/js/dolden\_em3d.zip}{http://www.fantascienza.net/leonardo/js/dolden\_em3d.zip}


\subsubsection{\texttt{tsp}}

Este programa implementa una heurística para resolver el problema del viajante
(\emph{traveling salesman problem}) utilizando árboles binarios balanceados. El
algoritmo utilizado es el descripto por Karp \hyperlink{kar77}{{[}KAR77{]}}.

Código fuente disponible en:
\href{http://www.fantascienza.net/leonardo/js/dolden\_tsp.zip}{http://www.fantascienza.net/leonardo/js/dolden\_tsp.zip}


\subsubsection{\texttt{voronoï}}

Este programa genera un conjunto aleatorio de puntos y computa su diagrama de
Voronoï, una construcción geométrica que permite construir una partición del
plano euclídeo, utilizando el algoritmo descripto por Guibas \& Stolfi \hyperlink{gs85}{{[}GS85{]}}.

Código fuente disponible en: \href{http://codepad.org/xGDCS3KO}{http://codepad.org/xGDCS3KO}
\hypertarget{sol-bench-real}{}

\subsection{Programas \emph{reales}}

\href{http://code.google.com/p/dil/}{Dil} (escrito en su mayor parte por Aziz Köksal y publicado bajo licencia
\href{http://www.gnu.org/copyleft/gpl.html}{GPL}) es, lamentablemente, el único programa real hallado que, a pesar de
estar incompleto, es lo suficientemente grande, mantenido y estable como para
ser incluido en el banco de pruebas. Se trata de un compilador de \href{http://www.digitalmars.com/d/}{D} escrito
en \href{http://www.digitalmars.com/d/}{D} y está incompleto porque no puede generar código (falta implementar el
análisis semántico y la generación de código). Es principalmente utilizado
para generar documentación a partir del código.

El programa está compuesto por:
\begin{itemize}
\item {} 
32.000 líneas de código fuente (aproximadamente).

\item {} 
86 módulos (o archivos).

\item {} 
322 diferentes tipos de datos definidos por el usuario, de los cuales 34 son
tipos \emph{livianos} (\code{struct}) y 288 tipos polimórficos (\code{class}), de los
que 260 son subtipos (sub-clases).

\end{itemize}

Puede observarse entonces que a pesar de ser incompleto, es una pieza de
software bastante compleja y de dimensión considerable.

Además, al interpretar código fuente se hace un uso intensivo de cadenas de
texto que en general presentan problemas muy particulares por poder ser
objetos extremadamente pequeños y de tamaños poco convencionales (no múltiplos
de palabras, por ejemplo). A su vez, el texto interpretado es convertido a una
representación interna en forma de árbol (o \emph{árbol de sintaxis abstracta})
modelado por tipos \emph{livianos} y polimórficos que están organizados en arreglos
dinámicos contiguos y asociativos (que usan muchos servicios del recolector).
Finalmente estos objetos son manipulados para obtener y generar la información
necesaria, creando y dejando de usar objetos constantemente (pero no como
única forma de procesamiento, como otras pruebas sintetizadas).

Por último, a diferencia de muchos otros programas escritos en \href{http://www.digitalmars.com/d/}{D}, que dadas
algunas de las ineficiencias del recolector invierten mucho trabajo en limitar
su uso, este programa no está escrito pensando en dichas limitaciones, por lo
que muestra un funcionamiento muy poco sesgado por estas infortunadas
circunstancias.

Por todas estas razones, \href{http://code.google.com/p/dil/}{Dil} es el ejemplar que tal vez mejor sirve a la hora
de medir de forma realista los resultados obtenidos o los avances realizados.
Si bien, como se ha dicho anteriormente, las demás pruebas del banco pueden
ser útiles para encontrar problemas muy particulares, está es la que da una
lectura más cercana a la realidad del uso de un recolector.
\hypertarget{sol-mod}{}

\section{Modificaciones propuestas}

Se decide realizar todas las modificaciones al recolector actual de forma
progresiva e incremental, partiendo como base del recolector de la versión
0.99.9 de \href{http://www.dsource.org/projects/tango}{Tango}.  Las razones que motivan esta decisión son varias; por un
lado es lo más apropiado dados los requerimientos claves mencionados al
principio de este capítulo. Por ejemplo, al hacer cambios incrementales es más
fácil comprobar que la eficiencia no se aleja mucho del actual con cada
modificación y una modificación gradual impone menos resistencia a la
aceptación del nuevo recolector.

Además la construcción de un recolector de cero es una tarea difícil
considerando que un error en el recolector es extremadamente complejo de
rastrear, dado que en general el error se detecta en el \emph{mutator} y en una
instancia muy posterior al origen real del error. Esto ha sido comprobado de
forma práctica, dado que, a modo de ejercicio para interiorizarse en el
funcionamiento del \emph{runtime} de \href{http://www.digitalmars.com/d/}{D}, primero se ha construido desde cero una
implementación de un recolector \emph{naïve}, resultando muy difícil su depuración
por las razones mencionadas. Por el contrario, comenzar con un recolector en
funcionamiento como base hace más sencillo tanto probar cada pequeña
modificación para asegurar que no introduce fallos, como encontrar y reparar
los fallos cuando estos se producen, ya que el código incorrecto introducido
está bien aislado e identificado.

A continuación se hace un recorrido sobre cada una de las mejoras propuestas,
y en los casos en los que la mejora propone un cambio algorítmico, se analiza
la corrección del algoritmo resultante, partiendo de la base de que el
algoritmo tomado como punto de partida es un marcado y barrido que utiliza la
abstracción tricolor para hacer la fase de marcado de forma iterativa (ver
\hyperlink{gc-mark-sweep}{\emph{Marcado y barrido}} y \hyperlink{gc-intro-tricolor}{\emph{Abstracción tricolor}}), cuya corrección ya está
probada en la literatura preexistente.


\hypertarget{sol-config}{}\subsection{Configurabilidad}

Una de las primeras mejoras propuestas es la posibilidad de configurar el
recolector de forma más sencilla. El requerimiento mínimo es la posibilidad de
configurar el recolector sin necesidad de recompilarlo. La complejidad de esto
surge de que el recolector debe ser transparente para el programa del usuario.

Configurar el recolector en tiempo de compilación del programa del usuario
probablemente requeriría modificar el compilador, y además, si bien es una
mejora sustancial a la configuración en tiempo de compilación del recolector,
no termina de ser completamente conveniente para realizar pruebas reiteradas
con un mismo programa para encontrar los mejores valores de configuración para
ese programa en particular.

Por otro lado, permitir configurar el recolector en tiempo de ejecución, una
vez que su estructura interna ya fue definida y creada, puede ser no solo
tedioso y complejo, además ineficiente, por lo tanto esta opción también se
descarta.

Finalmente, lo que parece ser más apropiado para un recolector, es permitir la
configuración en \emph{tiempo de inicialización}. Es decir, configurar el
recolectar sin necesidad de recompilar ni el programa del usuario ni el
recolector, pero antes de que el programa del usuario inicie, de manera que
una vez iniciado el recolector con ciertos parámetros, éstos no cambien nunca
más en durante la vida del programa.

Este esquema provee la mejor relación entre configurabilidad, conveniencia,
eficiencia y simplicidad. Una posibilidad para lograr esto es utilizar
parámetros de línea de comandos, sin embargo no parece ni sencillo (proveer
una forma de leer los parámetros de línea de comandos requiere cambios en el
\emph{runtime}) ni apropiado (el recolector debería ser lo más transparente posible
para el programa del usuario).

Otra posibilidad es utilizar variables de entorno, que parece ser la opción
más sencilla y apropiada. Sencilla porque las variables de entorno pueden ser
leídas directamente al inicializar el recolector sin necesidad de cooperación
alguna del \emph{runtime}, a través de \emph{\texttt{getenv(3)}}. Apropiada porque, si
bien el problema de invasión del programa del usuario también existe, es una
práctica más frecuente y aceptada la configuración de módulos internos
o bibliotecas compartidas a través de variables de entorno.

Por último, antes de comenzar a usar este esquema de configuración, se
verifica que tomar ciertas decisiones en tiempo de ejecución no impacten en la
eficiencia del recolector. Para esto se convierten algunas opciones que antes
eran solo seleccionables en tiempo de compilación del recolector para que
puedan ser seleccionables en tiempo de inicialización y se comprueba que no
hay una penalización apreciable.


\hypertarget{sol-config-spec}{}\subsubsection{Especificación de opciones}

Para especificar opciones de configuración, hay que hacerlo a través de la
variable de entorno de nombre \index{D\_GC\_OPTS}\index{variables de entorno!D\_GC\_OPTS}\textbf{D\_GC\_OPTS}. El valor de esa variable es
interpretado de la siguiente manera (en formato similar a \hyperlink{term-bnf}{\emph{BNF}}):


\begin{productionlist}
\production{D\_GC\_OPTS}{ \token{\code{option}} ( `:' \token{\code{option}} )* \textless{}lista de opciones\textgreater{}}
\production{option}{ \token{\code{name}} {[} `=' \token{\code{value}} {]}}
\production{name}{ \token{\code{namec}} \token{\code{namec}}*                \textless{}nombre de la opción\textgreater{}}
\production{value}{ \token{\code{valuec}}*                      \textless{}valor de la opción\textgreater{}}
\production{namec}{ \token{\code{valuec}} - `='}
\production{valuec}{ {[}0x01-0xFF{]} - `:'             \textless{}cualquiera salvo `\textbackslash{}0' y `:'\textgreater{}}
\end{productionlist}


Es decir, se compone de una lista de opciones separadas por \textbf{:}. Cada opción
se especifica con un nombre, opcionalmente seguido por un valor (separados por
\textbf{=}).

El valor de una opción puede ser un texto arbitrario (exceptuando los
caracteres \code{'\textbackslash{}0'} y \code{':'} y de longitud máxima 255), pero cada opción lo
interpreta de forma particular. Como caso general, hay opciones booleanas, que
toman como valor verdadero un cualquier número distinto de 0 (o si el valor es
vació, es decir, solo se indica el nombre de la opción), y como valor falso
cualquier otro texto.

A continuación se listan las opciones reconocidas por el recolector (indicando
el formato del valor de la opción de tener uno especial):
\begin{description}
\item[{\code{mem\_stomp}}] \leavevmode\\
Esta es una opción (booleana) disponible en el recolector original, pero
que se cambia para que sea configurable en tiempo de inicialización
(estando desactivada por omisión). Activa la opción \code{MEMSTOMP} descripta
en \hyperlink{dgc-debug}{\emph{Herramientas para depuración}}.

\item[{\code{sentinel}}] \leavevmode\\
Esta opción es también booleana (desactivada por omisión), está disponible
en el recolector original, y se la cambia para sea configurable en tiempo
de inicialización. Activa la opción \code{SENTINEL} descripta en
\hyperlink{dgc-debug}{\emph{Herramientas para depuración}}.

\item[{\code{pre\_alloc}}] \leavevmode\\
Esta opción permite crear una cierta cantidad de \emph{pools} de un tamaño
determinado previo a que inicie el programa. Si se especifica solo un
número, se crea un \emph{pool} con ese tamaño en MiB.  Si, en cambio, se
especifica una cadena del tipo \code{3x1}, el primer número indica la cantidad
de \emph{pools} y el segundo el tamaño en MiB de cada uno (3 \emph{pools} de 1MiB en
este caso). Ver \hyperlink{sol-pre-alloc}{\emph{Pre-asignación de memoria}} más adelante para más detalles sobre
la utilidad de esta opción.

\item[{\code{min\_free}}] \leavevmode\\
El valor de esta opción indica el porcentaje mínimo del \emph{heap} que debe
quedar libre luego de una recolección. Siendo un porcentaje, solo se
aceptan valores entre 0 y 100, siendo su valor por omisión 5. Ver
\hyperlink{sol-ocup}{\emph{Mejora del factor de ocupación del heap}} más adelante para más detalles sobre su propósito.

\item[{\code{malloc\_stats\_file}}] \leavevmode\\
Esta opción sirve para especificar un archivo en el cual escribir un
reporte de todas la operaciones de pedido de memoria realizadas por el
programa (durante su tiempo de vida).  Ver \hyperlink{sol-stats}{\emph{Recolección de estadísticas}} más adelante
para más detalles sobre la información provista y el formato del reporte.

\item[{\code{collect\_stats\_file}}] \leavevmode\\
Esta opción sirve para especificar un archivo en el cual escribir un
reporte de todas las recolecciones hechas durante el tiempo de vida del
programa.  Ver \hyperlink{sol-stats}{\emph{Recolección de estadísticas}} más adelante para más detalles sobre la
información provista y el formato del reporte.

\item[{\code{conservative}}] \leavevmode\\
Esta opción booleana permite desactivar el escaneo preciso del \emph{heap},
forzando al recolector a ser completamente conservativo (excepto por los
bloques con el atributo \code{NO\_SCAN} que siguen sin ser escaneados). Ver
\hyperlink{sol-precise}{\emph{Marcado preciso}} más adelante para más detalles sobre la existencia de esta opción.

\item[{\code{fork}}] \leavevmode\\
Esta opción booleana (activada por omisión) permite seleccionar si el
recolector debe correr la fase de marcado en paralelo o no (es decir, si el
recolector corre de forma concurrente con el \emph{mutator}).  Para más detalles
ver \hyperlink{sol-fork}{\emph{Marcado concurrente}} más adelante.

\item[{\code{eager\_alloc}}] \leavevmode\\
Esta opción booleana (activada por omisión), sólo puede estar activa si
\code{fork} también lo está y sirve para indicar al recolector que reserve un
nuevo \emph{pool} de memoria cuando una petición no puede ser satisfecha, justo
antes de lanzar la recolección concurrente. Ver \hyperlink{sol-eager-alloc}{\emph{Creación ansiosa de pools (eager allocation)}} más
adelante para más detalles sobre el propósito de esta opción.

\item[{\code{early\_collect}}] \leavevmode\\
Esta opción booleana (desactivada por omisión), también sólo puede estar
activa si \code{fork} está activa y sirve para indicar al recolector que lance
una recolección (concurrente) antes de que la memoria libre se termine (la
recolección temprana será disparada cuando el porcentaje de memoria libre
sea menor a \code{min\_free}). Ver \hyperlink{sol-early-collect}{\emph{Recolección temprana (early collection)}} más adelante para
más detalles sobre el propósito de esta opción.

\end{description}

Cualquier opción o valor no reconocido es ignorado por el recolector. Se
utilizan los valores por omisión de las opciones que no fueron especificadas,
o cuyos valores no pudieron ser interpretados correctamente.

Para cambiar la configuración del recolector se puede invocar el programa de
la siguiente manera (usando un intérprete de comandos del tipo \emph{bourne
shell}):

\begin{Verbatim}[commandchars=\\\{\}]
D\PYGZus{}GC\PYGZus{}OPTS=conservative:eager\PYGZus{}alloc=0:early\PYGZus{}collect=1:pre\PYGZus{}alloc=2x5 ./prog
\end{Verbatim}

En este ejemplo, se activan las opciones \code{conservative} y \code{early\_collect},
se desactiva \code{eager\_alloc} y se crean 2 \emph{pools} de 5MiB cada uno al
inicializar el recolector.


\subsection{Reestructuración y cambios menores}

Si bien se decide no comenzar una implementación desde cero, se ha mostrado
(ver \hyperlink{dgc-bad-code}{\emph{Complejidad del código y documentación}}) que la implementación actual es lo suficientemente
desprolija como para complicar su modificación. Es por esto que se hacen
algunas reestructuraciones básicas del código, reescribiendo o saneando de
forma incremental todas aquellas partes que complican su evolución.

Además de las modificaciones puramente estéticas (aunque no por eso menos
valuables, ya que la legibilidad y simplicidad del código son un factor
fundamental a la hora de ser mantenido o extendido), se hacen otras pequeñas
mejoras, que se detallan a continuación.


\subsubsection{Remoción de memoria \emph{no-encomendada}}

Se elimina la distinción entre memoria \emph{encomendada} y \emph{no-encomendada} (ver
\hyperlink{dgc-committed}{\emph{Memoria encomendada}}), pasando a estar \emph{encomendada} toda la memoria
administrada por el recolector.

Si bien a nivel de eficiencia este cambio no tuvo impacto alguno (cuando en un
principio se especuló con que podría dar alguna ganancia en este sentido), se
elimina el concepto de memoria \emph{encomendada} para quitar complejidad al
código.

Esta mejora no afecta a la corrección del algoritmo, ya que a nivel lógico el
recolector solo ve la memoria \emph{encomendada}.
\hypertarget{sol-minor-findsize}{}

\subsubsection{Caché de \texttt{Pool.findSize()}}

Se crea un caché de tamaño de bloque para el método \code{findSize()} de un
\emph{pool}. Esto acelera considerablemente las operaciones que necesitan pedir el
tamaño de un bloque reiteradamente, por ejemplo, al añadir nuevos elementos
a un arreglo dinámico. En esencia es una extensión a una de las optimizaciones
propuestas por Vladimir Panteleev \hyperlink{pan09}{{[}PAN09{]}}, que propone un caché global para
todo el recolector en vez de uno por \emph{pool}.

Esta mejora tampoco afecta a la corrección del algoritmo, ya que nuevamente no
afecta su comportamiento a nivel lógico, solo cambia detalles en la
implementación de forma transparentes para el algoritmo de recolección.


\subsubsection{Optimizaciones sobre \texttt{findPool()}}

Al analizar los principales cuellos de botella del recolector, es notoria la
cantidad de tiempo que pasa ejecutando la función \code{findPool()}, que dado un
puntero devuelve el \emph{pool} de memoria al cual pertenece. Es por esto que se
minimiza el uso de esta función. Además, dado que los \emph{pools} de memoria están
ordenados por el puntero de comienzo del bloque de memoria manejado por el
\emph{pool}, se cambia la búsqueda (originalmente lineal) por una búsqueda binaria.
Finalmente, dado que la lista de libre está construida almacenando el puntero
al siguiente en las mismas celdas que componen la lista, se almacena también
el puntero al \emph{pool} al que dicha celda pertenece (dado que la celda más
pequeña es de 16 bytes, podemos garantizar que caben dos punteros, incluso
para arquitecturas de 64 bits). De esta manera no es necesario usar
\code{findPool()} al quitar una celda de la lista de libres.

Una vez más, la mejora no afecta la corrección del código.
\hypertarget{sol-pre-alloc}{}

\subsubsection{Pre-asignación de memoria}

Esta opción permite crear una cierta cantidad de \emph{pools} de un tamaño
determinado previo a que inicie el programa. Normalmente el recolector no
reserva memoria hasta que el programa lo pida. Esto puede llegar a evitar
que un programa haga muchas recolecciones al comenzar, hasta que haya
cargado su conjunto de datos de trabajo.

Se han analizado varios valores por omisión pero ninguno es consistentemente
mejor que comenzar sin memoria asignada, por lo tanto no se cambia el
comportamiento original, pero se agrega una opción (ver \code{pre\_alloc} en
\hyperlink{sol-config-spec}{\emph{Especificación de opciones}}) para que el usuario pueda experimentar con cada
programa en particular si esta opción es beneficiosa.

Esta opción tampoco cambia la corrección del algoritmo de recolección, solo
sus condiciones iniciales.
\hypertarget{sol-ocup}{}

\subsubsection{Mejora del factor de ocupación del \emph{heap}}

El factor de ocupación del \emph{heap} debe ser apropiado por dos razones. Por un
lado, si el \emph{heap} está demasiado ocupado todo el tiempo, serán necesarias
muchas recolecciones, lo que puede llegar a ser extremadamente ineficiente en
casos patológicos (ver \hyperlink{dgc-bad-ocup}{\emph{Factor de ocupación del heap}}). Por otro lado, si el tamaño del
\emph{heap} es extremadamente grande (en comparación con el tamaño real del grupo
de trabajo del programa), se harán pocas recolecciones pero cada una es muy
costosa, porque el algoritmo de marcado y barrido es $O(\lvert Heap
\rvert)$ (ver \hyperlink{gc-mark-sweep}{\emph{Marcado y barrido}}). Además la afinidad del caché va a ser
extremadamente pobre.

Para mantener el factor de ocupación dentro de límites razonables, se agrega
la opción \code{min\_free} (ver \hyperlink{sol-config-spec}{\emph{Especificación de opciones}}). Esta opción indica el
recolector cual debe ser el porcentaje mínimo del \emph{heap} que debe quedar libre
luego de una recolección. En caso de no cumplirse, se pide más memoria al
sistema operativo para cumplir este requerimiento. Además, luego de cada
recolección se verifica que el tamaño del \emph{heap} no sea mayor a \code{min\_free},
para evitar que el \emph{heap} crezca de forma descontrolada. Si es mayor
a \code{min\_free} se intenta minimizar el uso de memoria liberando \emph{pools} que
estén completamente desocupados, mientras que el factor de ocupación siga
siendo mayor a \code{min\_free}. Si liberar un \emph{pool} implica pasar ese límite, no
se libera y se pasa a analizar el siguiente y así sucesivamente.

Esta modificación no afecta a la corrección del algoritmo, ya que no lo afecta
directamente.


\subsubsection{Modificaciones descartadas}

Se realizan varias otras modificaciones, con la esperanza de mejorar la
eficiencia del recolector, pero que, al contrario de lo esperado, empeoran la
eficiencia o la mejoran de forma muy marginal en comparación con la
complejidad agregada.

Probablemente el caso más significativo, y por tanto el único que vale la pena
mencionar, es la conversión de marcado iterativo a marcado recursivo y luego
a un esquema híbrido. Como se describe en \hyperlink{dgc-bad}{\emph{Problemas y limitaciones}}, el marcado iterativo
tiene sus ventajas, pero tiene desventajas también. La conversión a puramente
recursivo resulta impracticable dado que desemboca en errores de
desbordamiento de pila.

Por lo tanto se prueba con un esquema híbrido, poniendo un límite a la
recursividad, volviendo al algoritmo iterativo cuando se alcanza este límite.

La implementación del algoritmo híbrido consiste en los siguientes cambios
sobre el algoritmo original (ver \hyperlink{dgc-algo-mark}{\emph{Fase de marcado}}):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{false}
   \PYG{k}{global} \PYG{n}{depth} \PYG{o}{=} \PYG{l+m+mi}{0}                                \PYG{c+c1}{// Agregado}
   \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{clear\PYGZus{}mark\PYGZus{}scan\PYGZus{}bits}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}free\PYGZus{}lists}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}static\PYGZus{}data}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{push\PYGZus{}registers\PYGZus{}into\PYGZus{}stack}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{thread\PYGZus{}self}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end} \PYG{o}{=} \PYG{n+nb}{get\PYGZus{}stack\PYGZus{}top}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}stacks}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{pop\PYGZus{}registers\PYGZus{}from\PYGZus{}stack}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}user\PYGZus{}roots}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}heap}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{end}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pointer} \PYG{o}{=} \PYG{n}{begin}
   \PYG{k}{global} \PYG{n}{depth}\PYG{o}{+}\PYG{o}{+}                                  \PYG{c+c1}{// Agregado}
   \PYG{k}{while} \PYG{n}{pointer} \PYG{o}{\textless{}} \PYG{n}{end}
      \PYG{p}{[}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{,} \PYG{n}{block}\PYG{p}{]} \PYG{o}{=} \PYG{n}{find\PYGZus{}block}\PYG{p}{(}\PYG{n}{pointer}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{k}{not} \PYG{n+nb}{null} \PYG{k}{and} \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{k}{is} \PYG{n+nb}{false}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{true}
         \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{k}{is} \PYG{n+nb}{false}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{true}
            \PYG{k}{if} \PYG{p}{(}\PYG{k}{global} \PYG{n}{depth} \PYG{o}{\textgreater{}} \PYG{n}{MAX\PYGZus{}DEPTH}\PYG{p}{)}          \PYG{c+c1}{//}
               \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{true}                 \PYG{c+c1}{//}
            \PYG{k}{else}                                   \PYG{c+c1}{// Agregado}
               \PYG{k}{foreach} \PYG{n}{ptr} \PYG{k}{in} \PYG{n}{block}\PYG{p}{.}\PYG{n}{words}          \PYG{c+c1}{//}
                  \PYG{n}{mark}\PYG{p}{(}\PYG{n}{ptr}\PYG{p}{)}                        \PYG{c+c1}{//}
   \PYG{k}{global} \PYG{n}{depth}\PYG{o}{-}\PYG{o}{-}                                  \PYG{c+c1}{//}
\end{Verbatim}

Al analizar los resultados de de esta modificación, se observa una mejoría muy
level, para valores de \code{MAX\_DEPTH} mayores a cero (en algunos casos bastante
mayores). En general para \code{MAX\_DEPTH} cero (es decir, usando el algoritmo de
forma completamente iterativa) los resultados son peores, dado que se paga el
trabajo extra sin ganancia alguna. En la figura \vref{fig:sol-mark-rec} se
puede ver, por ejemplo, el tiempo total de ejecución de \href{http://code.google.com/p/dil/}{Dil} al generar la
documentación completa del código de \href{http://www.dsource.org/projects/tango}{Tango}, según varía el valor de
\code{MAX\_DEPTH}.
\begin{figure}[btp]
\centering

\includegraphics{sol-mark-rec-dil.pdf}
\caption[Análisis de tiempo total de ejecución en función del valor de
\code{MAX\_DEPTH}]{Tiempo total de ejecución de \href{http://code.google.com/p/dil/}{Dil} al generar la documentación completa del
código de \href{http://www.dsource.org/projects/tango}{Tango} en función del valor de \code{MAX\_DEPTH}. El rombo no
pertenece a ningún nivel de recursividad, representa el tiempo de ejecución
del algoritmo original (puramente iterativo).}
\label{fig:sol-mark-rec}
\end{figure}


Dado que aumentar el nivel máximo de recursividad significa un uso mayor del
\emph{stack}, y que esto puede impactar en el usuario (si el usuario tuviera un
programa que esté al borde de consumir todo el \emph{stack}, el recolector podría
hacer fallar al programa de una forma inesperada para el usuario, problema que
sería muy difícil de depurar para éste), y que los resultados obtenidos no son
rotundamente superiores a los resultados sin esta modificación, se opta por no
incluir el cambio. Tampoco vale la pena incluirlo como una opción con valor
por omisión 0 porque, como se ha dicho, para este caso el resultado es incluso
peor que sin la modificación.

Esta modificación mantiene la corrección del recolector dado que tampoco
modifica el algoritmo sino su implementación. Además ambos casos extremos son
correctos (si \code{MAX\_DEPTH} es 0, el algoritmo es puramente iterativo y si
pudiera ser infinito resultaría en el algoritmo puramente recursivo).
\hypertarget{sol-stats}{}

\subsection{Recolección de estadísticas}

Un requerimiento importante, tanto para evaluar los resultados de este trabajo
como para analizar el comportamiento de los programas estudiados, es la
recolección de estadísticas. Hay muchos aspectos que pueden ser analizados
a la hora de evaluar un recolector, y es por esto que se busca que la
recolección de datos sea lo más completa posible.

Con este objetivo, se decide recolectar datos sobre lo que probablemente sean
las operaciones más importantes del recolector: asignación de memoria
y recolección.

Todos los datos recolectados son almacenados en archivos que se especifican
a través de opciones del recolector (ver \hyperlink{sol-config-spec}{\emph{Especificación de opciones}}). Los archivos
especificados debe poder ser escritos (y creados de ser necesario) por el
recolector (de otra forma se ignora la opción). El conjunto de datos
recolectados son almacenados en formato \hyperlink{term-csv}{\emph{CSV}} en el archivo, comenzando
con una cabecera que indica el significado de cada columna.

Los datos recolectados tienen en general 4 tipos de valores diferentes:
\begin{description}
\item[{Tiempo}] \leavevmode\\
Se guarda en segundos como número de punto flotante (por ejemplo \code{0.12}).

\item[{Puntero}] \leavevmode\\
Se guarda en forma hexadecimal (por ejemplo \code{0xa1b2c3d4}).

\item[{Tamaño}] \leavevmode\\
Se guarda como un número decimal, expresado en bytes (por ejemplo \code{32}).

\item[{Indicador}] \leavevmode\\
Se guarda como el número \code{0} si es falso o \code{1} si es verdadero.

\end{description}

Esta modificación mantiene la corrección del recolector dado que no hay cambio
algorítmico alguno.


\subsubsection{Asignación de memoria}

La recolección de datos sobre asignación de memoria se activa asignando un
nombre de archivo a la opción \code{malloc\_stats\_file}. Por cada asignación de
memoria pedida por el programa (es decir, por cada llamada a la función
\code{gc\_malloc()}) se guarda una fila con los siguientes datos:
\begin{enumerate}
\item {} 
Cantidad de segundos que pasaron desde que empezó el programa (\emph{timestamp}).

\item {} 
Tiempo total que tomó la asignación de memoria.

\item {} 
Valor del puntero devuelto por la asignación.

\item {} 
Tamaño de la memoria pedida por el programa.

\item {} 
Si esta petición de memoria disparó una recolección o no.

\item {} 
Si debe ejecutarse un \emph{finalizador} sobre el objeto (almacenado en la
memoria pedida) cuando ésta no sea más alcanzable (cuando sea barrido).

\item {} 
Si objeto carece de punteros (es decir, no debe ser escaneada).

\item {} 
Si objeto no debe ser movido por el recolector.

\item {} 
Puntero a la información sobre la ubicación de los punteros del objeto.

\item {} 
Tamaño del tipo del objeto.

\item {} 
Primera palabra con los bits que indican que palabras del tipo deben ser
escaneados punteros y cuales no (en hexadecimal).

\item {} 
Primera palabra con los bits que indican que palabras del tipo son
punteros garantizados (en hexadecimal).

\end{enumerate}

Como puede apreciarse, la mayor parte de esta información sirve más para
analizar el programa que el recolector. Probablemente solo el punto 2 sea de
interés para analizar como se comporta el recolector.

El punto 8 es completamente inútil, ya que el compilador nunca provee esta
información, pero se la deja por si en algún momento comienza a hacerlo. Los
puntos 9 a 12 proveen información sobre el tipo del objeto almacenado, útil
para un marcado preciso (ver \hyperlink{sol-precise}{\emph{Marcado preciso}}).

El punto 6 indica, indirectamente, cuales de los objetos asignados son
\emph{pesados}, ya que éstos son los únicos que pueden tener un \emph{finalizador}.
Además, a través de los puntos 4 y 10 es posible inferir si lo que va
almacenarse es un objeto solo o un arreglo de objetos.


\subsubsection{Recolección de basura}

Los datos sobre las recolecciones realizadas se guardan al asignar un nombre
de archivo a la opción \code{collect\_stats\_file}. Cada vez que se dispara una
recolección \footnote{
Esto es en el sentido más amplio posible. Por ejemplo, cuando
se utiliza marcado concurrente (ver \hyperlink{sol-fork}{\emph{Marcado concurrente}}), se guarda esta
información incluso si ya hay una recolección activa, pero el tiempo de
pausa de los hilos será -1 para indicar que en realidad nunca fueron
pausados.
} (es decir, cada vez que se llama a la función
\code{fullcollect()}) se guarda una fila con los siguientes datos:
\begin{enumerate}
\item {} 
Cantidad de segundos que pasaron desde que empezó el programa (\emph{timestamp}).

\item {} 
Tiempo total que tomó la asignación de memoria que disparó la recolección.

\item {} 
Tiempo total que tomó la recolección.

\item {} 
Tiempo total que deben pausarse todos los hilos (tiempo de
\emph{stop-the-world}).

\item {} 
Cantidad de memoria usada antes de la recolección.

\item {} 
Cantidad de memoria libre antes de la recolección.

\item {} 
Cantidad de memoria desperdiciada \footnote{
Memoria \emph{desperdiciada} se refiere a memoria que directamente
no puede utilizarse debido a la fragmentación. Si por ejemplo, se piden 65
bytes de memoria, dada la organización del \emph{heap} en bloques (ver
\hyperlink{dgc-org}{\emph{Organización del heap}}), el recolector asignará un bloque de 128 bytes, por lo
tanto 63 bytes quedarán desperdiciados.
} antes de la recolección.

\item {} 
Cantidad de memoria utilizada por el mismo recolector antes de la
recolección (para sus estructuras internas).

\item {} 
Cantidad de memoria usada después de la recolección.

\item {} 
Cantidad de memoria libre después de la recolección.

\item {} 
Cantidad de memoria desperdiciada después de la recolección.

\item {} 
Cantidad de memoria utilizada por el mismo recolector después de la
recolección.

\end{enumerate}

Si bien el punto 4 parece ser el más importante para un programa que necesita
baja latencia, dado el \emph{lock} global del recolector, el punto 2 es
probablemente el valor más significativo en este aspecto, dado que, a menos
que el programa en cuestión utilice muy poco el recolector en distintos hilos,
los hilos se verán pausados de todas formas cuando necesiten utilizar el
recolector.
\hypertarget{sol-precise}{}

\subsection{Marcado preciso}

Para agregar el soporte de marcado preciso se aprovecha el trabajo realizado
por Vincent Lang (ver \hyperlink{dgc-via-art}{\emph{Principales categorías del estado del arte}}) \hyperlink{dbz3463}{{[}DBZ3463{]}}, gracias a que se basa en
\href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0} y \href{http://www.dsource.org/projects/tango}{Tango}, al igual que este trabajo. Dado el objetivo y entorno
común, se abre la posibilidad de adaptar sus cambios a este trabajo,
utilizando una versión modificada de \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} (dado que los cambios aún no están
integrados al compilador oficial todavía).


\subsubsection{Información de tipos provista por el compilador}

Con éstas modificaciones, el compilador en cada asignación le pasa al
recolector información sobre los punteros del tipo para el cual se pide la
memoria. Esta información se pasa como un puntero a un arreglo de palabras con
la estructura mostrada en la figura \vref{fig:sol-ptrmap} y que se describe
a continuación.
\begin{table}[btp]
\centering

\includegraphics{aafig-685d0528f3aa100260e7ad98bd831c0ced0f76c0.pdf}
\caption[Estructura de la información de tipos provista por el compilador]{Estructura de la información de tipos provista por el compilador.}
\label{fig:sol-ptrmap}
\end{table}

\begin{itemize}
\item {} 
La primera palabra indica el tamaño, en \textbf{cantidad de palabras}, del tipo
para el cual se pide la memoria ($N$).

\item {} 
Las siguientes $ceil(\frac{N}{BPW})$ palabras indican,
como un conjunto de bits, qué palabras deben ser escaneadas por el
recolector como si fueran punteros (donde $BPW$ indica la cantidad de
bits por palabra, por ejemplo 32 para x86).

\item {} 
Las siguientes $ceil(\frac{N}{BPW})$ palabras son otro conjunto de
bits indicando qué palabras son realmente punteros.

\end{itemize}

Los conjuntos de bits guardan la información sobre la primera palabra en el
bit menos significativo. Dada la complejidad de la representación, se ilustra
con un ejemplo. Dada la estructura:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{union} \PYG{n}{U} \PYG{p}{\PYGZob{}}
   \PYG{k+kt}{ubyte} \PYG{n}{ub}\PYG{p}{;}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{ptr}\PYG{p}{;}
\PYG{p}{\PYGZcb{}}

\PYG{k}{struct} \PYG{n}{S}
\PYG{p}{\PYGZob{}}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{begin1}\PYG{p}{;}                        \PYG{c+c1}{// 1 word}
   \PYG{k+kt}{byte}\PYG{p}{[}\PYG{n}{size\PYGZus{}t}\PYG{p}{.}\PYG{n}{sizeof} \PYG{p}{*} \PYG{l+m+mi}{14} \PYG{p}{+} \PYG{l+m+mi}{1}\PYG{p}{]} \PYG{n}{bytes}\PYG{p}{;}  \PYG{c+c1}{// 15 words}
   \PYG{c+c1}{// el compilador agrega bytes de "padding" para alinear}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{middle}\PYG{p}{;}                        \PYG{c+c1}{// 1 word}
   \PYG{n}{size\PYGZus{}t}\PYG{p}{[}\PYG{l+m+mi}{14}\PYG{p}{]} \PYG{n}{ints}\PYG{p}{;}                     \PYG{c+c1}{// 14 words}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{end1}\PYG{p}{;}                          \PYG{c+c1}{// 1 words}
   \PYG{c+c1}{// hasta acá se almacenan los bits en la primera palabra}
   \PYG{k+kt}{void}\PYG{p}{*} \PYG{n}{begin2}\PYG{p}{;}                        \PYG{c+c1}{// 1 words}
   \PYG{k+kt}{int} \PYG{n}{i}\PYG{p}{;}                               \PYG{c+c1}{// 1 word}
   \PYG{n}{U} \PYG{n}{u}\PYG{p}{;}                                 \PYG{c+c1}{// 1 word}
   \PYG{n}{S}\PYG{p}{*} \PYG{n}{s}\PYG{p}{;}                                \PYG{c+c1}{// 1 word}
\PYG{p}{\PYGZcb{}}
\end{Verbatim}

El compilador genera la estructura que se muestra en la figura
\vref{fig:sol-ptrmap-example} (asumiendo una arquitectura de 32 bits). Como
puede apreciarse, el miembro \code{u}, al ser una unión entre un puntero y un
dato común, el compilador no puede asegurar que lo que se guarda en esa
palabra sea realmente un puntero, pero indica que debe ser escaneado. El
recolector debe debe ser conservativo en este caso, y escanear esa palabra
como si fuera un puntero.
\begin{figure}[btp]
\centering

\includegraphics{aafig-0acb669e3da19d3b4385c2ed57ab971bbd755be2.pdf}
\caption[Ejemplo de estructura de información de tipos generada para el tipo \code{S}]{Ejemplo de estructura de información de tipos generada para el tipo \code{S}.}
\label{fig:sol-ptrmap-example}
\end{figure}


Si una implementación quisiera mover memoria (ver \hyperlink{gc-moving}{\emph{Movimiento de celdas}}), debería
mantener inmóvil a cualquier objeto que sea apuntado por una palabra de estas
características, ya que no es seguro actualizar la palabra con la nueva
posición el objeto movido. Es por esta razón que se provee desglosada la
información sobre lo que hay que escanear, y lo que es realmente un puntero
(que puede ser actualizado de forma segura por el recolector de ser
necesario).


\subsubsection{Implementación en el recolector}

La implementación está basada en la idea original de David Simcha, pero
partiendo de la implementación de Vincent Lang (que está basada en \href{http://www.dsource.org/projects/tango}{Tango})
y consiste en almacenar el puntero a la estructura con la descripción del tipo
generada por el compilador al final del bloque de datos. Este puntero solo se
almacena si el bloque solicitado no tiene el atributo \code{NO\_SCAN}, dado que en
ese caso no hace falta directamente escanear ninguna palabra del bloque.

En la figura \vref{fig:sol-ptrmap-blk} se puede ver, como continuación del
ejemplo anterior, como se almacenaría en memoria un objeto del tipo \code{S}.
\begin{figure}[btp]
\centering

\includegraphics{aafig-f51a59194ecde31d35c2ecae9e43427277097276.pdf}
\caption[Ejemplo de bloque que almacena un objeto de tipo \code{S} con información de
tipo]{Ejemplo de bloque que almacena un objeto de tipo \code{S} con información de
tipo.}
\label{fig:sol-ptrmap-blk}
\end{figure}


Un problema evidente de este esquema es que si el tamaño de un objeto se
aproxima mucho al tamaño de bloque (difiere en menos de una palabra), el
objeto ocupará el doble de memoria.

El algoritmo de marcado se cambia de la siguiente forma:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{c+c1}{// Agregado}
\PYG{k}{global} \PYG{n}{conservative\PYGZus{}ptrmap} \PYG{o}{=} \PYG{p}{[}\PYG{l+m+mi}{1}\PYG{p}{,} \PYG{l+m+mi}{1}\PYG{p}{,} \PYG{l+m+mi}{0}\PYG{p}{]}

\PYG{c+c1}{// Agregado}
\PYG{k}{function} \PYG{n}{must\PYGZus{}scan\PYGZus{}word}\PYG{p}{(}\PYG{n}{pos}\PYG{p}{,} \PYG{n}{bits}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{return} \PYG{n}{bits}\PYG{p}{[}\PYG{n}{pos} \PYG{o}{/} \PYG{n}{BITS\PYGZus{}PER\PYGZus{}WORD}\PYG{p}{]} \PYG{o}{\&} \PYG{p}{(}\PYG{l+m+mi}{1} \PYG{o}{\textless{}}\PYG{o}{\textless{}} \PYG{p}{(}\PYG{n}{pos} \PYG{o}{\%} \PYG{n}{BITS\PYGZus{}PER\PYGZus{}WORD}\PYG{p}{)}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{end}\PYG{p}{,} \PYG{n}{ptrmap}\PYG{p}{)} \PYG{k}{is}             \PYG{c+c1}{// Modificado}
   \PYG{n}{number\PYGZus{}of\PYGZus{}words\PYGZus{}in\PYGZus{}type} \PYG{o}{=} \PYG{n}{ptrmap}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}                 \PYG{c+c1}{// Agregado}
   \PYG{n}{size\PYGZus{}t}\PYG{o}{*} \PYG{n}{scan\PYGZus{}bits} \PYG{o}{=} \PYG{n}{ptrmap} \PYG{o}{+} \PYG{l+m+mi}{1}                      \PYG{c+c1}{// Agregado}
   \PYG{n}{pointer} \PYG{o}{=} \PYG{n}{begin}
   \PYG{k}{while} \PYG{n}{pointer} \PYG{o}{\textless{}} \PYG{n}{end}
      \PYG{k}{foreach} \PYG{n}{word\PYGZus{}pos} \PYG{k}{in} \PYG{l+m+mf}{0.}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}words\PYGZus{}in\PYGZus{}type}   \PYG{c+c1}{//}
         \PYG{k}{if} \PYG{k}{not} \PYG{n}{must\PYGZus{}scan\PYGZus{}word}\PYG{p}{(}\PYG{n}{word\PYGZus{}pos}\PYG{p}{,} \PYG{n}{scan\PYGZus{}bits}\PYG{p}{)}    \PYG{c+c1}{// Agregado}
            \PYG{k}{continue}                                   \PYG{c+c1}{//}
         \PYG{p}{[}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{,} \PYG{n}{block}\PYG{p}{]} \PYG{o}{=} \PYG{n}{find\PYGZus{}block}\PYG{p}{(}\PYG{n}{pointer}\PYG{p}{)}
         \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{k}{not} \PYG{n+nb}{null} \PYG{k}{and} \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{k}{is} \PYG{n+nb}{false}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{true}
            \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{k}{is} \PYG{n+nb}{false}
               \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{true}
               \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{true}
      \PYG{n}{pointer} \PYG{o}{+}\PYG{o}{=} \PYG{n}{number\PYGZus{}of\PYGZus{}words\PYGZus{}in\PYGZus{}type}               \PYG{c+c1}{// Modificado}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}heap}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{while} \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan}
      \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{false}
      \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
         \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
            \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}}\PYG{o}{=} \PYG{n}{PAGE} \PYG{c+c1}{// saltea FREE y CONTINUATION}
               \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
                  \PYG{k}{if} \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{k}{is} \PYG{n+nb}{true}
                     \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{false}
                     \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{PAGE} \PYG{c+c1}{// obj grande //}
                        \PYG{n}{begin} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{page}              \PYG{c+c1}{//}
                        \PYG{n}{end} \PYG{o}{=} \PYG{n}{find\PYGZus{}big\PYGZus{}object\PYGZus{}end}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)} \PYG{c+c1}{//}
                     \PYG{k}{else} \PYG{c+c1}{// objeto pequeño                   //}
                        \PYG{n}{begin} \PYG{o}{=} \PYG{n}{block}\PYG{p}{.}\PYG{n}{begin}                   \PYG{c+c1}{//}
                        \PYG{n}{end} \PYG{o}{=} \PYG{n}{block}\PYG{p}{.}\PYG{n}{end}                       \PYG{c+c1}{// Modificado}
                     \PYG{n}{ptrmap} \PYG{o}{=} \PYG{k}{global} \PYG{n}{conservative\PYGZus{}ptrmap}      \PYG{c+c1}{//}
                     \PYG{k}{if} \PYG{n}{NO\PYGZus{}SCAN} \PYG{k}{not} \PYG{k}{in} \PYG{n}{block}\PYG{p}{.}\PYG{n}{attrs}            \PYG{c+c1}{//}
                        \PYG{n}{end} \PYG{o}{-}\PYG{o}{=} \PYG{n}{size\PYGZus{}t}\PYG{p}{.}\PYG{n}{sizeof}                  \PYG{c+c1}{//}
                        \PYG{n}{ptrmap} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n}{size\PYGZus{}t}\PYG{o}{*}\PYG{p}{)} \PYG{o}{*}\PYG{n}{end}           \PYG{c+c1}{//}
                     \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{end}\PYG{p}{,} \PYG{n}{ptrmap}\PYG{p}{)}           \PYG{c+c1}{//}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}static\PYGZus{}data}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{static\PYGZus{}data}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{static\PYGZus{}data}\PYG{p}{.}\PYG{n}{end}\PYG{p}{,}
         \PYG{k}{global} \PYG{n}{conservative\PYGZus{}ptrmap}\PYG{p}{)}              \PYG{c+c1}{// Agregado}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}stacks}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{thread} \PYG{k}{in} \PYG{n}{threads}
      \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{thread}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{thread}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end}\PYG{p}{,}
            \PYG{k}{global} \PYG{n}{conservative\PYGZus{}ptrmap}\PYG{p}{)}                \PYG{c+c1}{// Agregado}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}user\PYGZus{}roots}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{root\PYGZus{}range} \PYG{k}{in} \PYG{n}{user\PYGZus{}roots}
      \PYG{n}{mark\PYGZus{}range}\PYG{p}{(}\PYG{n}{root\PYGZus{}range}\PYG{p}{.}\PYG{n}{begin}\PYG{p}{,} \PYG{n}{root\PYGZus{}range}\PYG{p}{.}\PYG{n}{end}\PYG{p}{,}
            \PYG{k}{global} \PYG{n}{conservative\PYGZus{}ptrmap}\PYG{p}{)}            \PYG{c+c1}{// Agregado}
\end{Verbatim}

Las funciones de asignación de memoria se modifican de forma similar, para
guardar el puntero a la información de tipos. Esta implementación utiliza solo
la información sobre que palabras hay que tratar como punteros (deben ser
escaneadas); la información sobre qué palabras son efectivamente punteros no
se utiliza ya que no se mueven celdas.

El algoritmo sigue siendo correcto, puesto que solamente se dejan de escanear
palabras que el compilador sabe que no pueden ser punteros. Si bien el
lenguaje permite almacenar punteros en una variable que no lo sea, esto es
comportamiento indefinido por lo tanto un programa que lo hace no es
considerado correcto, por lo cual el recolector tampoco debe ser correcto en
esas circunstancias.

Cabe destacar que la información de tipos solo se provee para objetos
almacenados en el \emph{heap}, el área de memoria estática, registros del
procesador y la pila de todos los hilos siguen siendo escaneados de forma
completamente conservativa. Se puede forzar el escaneo puramente conservativo
utilizando la opción \code{conservative} (ver \hyperlink{sol-config-spec}{\emph{Especificación de opciones}}).
\hypertarget{sol-fork}{}

\subsection{Marcado concurrente}

Finalmente se procede al objetivo primario de este trabajo, hacer que la fase
más costosa del recolector (el marcado) pueda correr de manera concurrente con
el \emph{mutator}, con el objeto principal de disminuir el tiempo de pausa.

Cabe aclarar, una vez más, que si bien los recolectores concurrentes buscan
disminuir solo el tiempo de \emph{stop-the-world}, en este caso es también
fundamental disminuir el tiempo máximo que está tomado el \emph{lock} global, dado
que ese tiempo puede convertirse en una pausa para todos los threads que
requieran servicios del recolector.

Se decide basar la implementación en el \emph{paper} ``Non-intrusive Cloning Garbage
Collector with Stock Operating System Support'' \hyperlink{rodr97}{{[}RODR97{]}} por las siguientes
razones principales:
\begin{itemize}
\item {} 
Su implementación encaja de forma bastante natural con el diseño del
recolector actual, por lo que requiere pocos cambios, lo que hace más
factible su aceptación.

\item {} 
Está basado en la llamada al sistema \emph{\texttt{fork(2)}}, que no solo está
muy bien soportada (y de manera muy eficiente) en \href{http://www.kernel.org/}{Linux}, debe estar
soportada en cualquier sistema operativo \hyperlink{term-posix}{\emph{POSIX}}.

\item {} 
No necesita instrumentar el código incluyendo barreras de memoria para
informar al recolector cuando cambia el grafo de conectividad. Este es un
aspecto fundamental, dada la filosofía de \href{http://www.digitalmars.com/d/}{D} de no pagar el precio de cosas
que no se usan. La penalización en la eficiencia solo se paga cuando corre
el recolector. Este aspecto también es crítico a la hora de evaluar la
aceptación de la solución por parte de la comunidad.

\item {} 
Dada su sencillez general, no es difícil ofrecer el algoritmo concurrente
como una opción, de manera que el usuario pueda optar por usarlo o no.

\end{itemize}


\subsubsection{Llamada al sistema \emph{fork}}

El término \emph{fork} proviene del inglés y significa \emph{tenedor} de manera textual,
pero se lo utiliza como analogía de una bifurcación. La operación crea una
copia (llamada \emph{hijo}) del proceso que la ejecuta (llamado \emph{padre}).

El punto más importante es que se crea un espacio de direcciones de memoria
separado para el proceso hijo y una copia exacta de todos los segmentos de
memoria del proceso padre. Es por esto que cualquier modificación que se haga
en el proceso padre, no se refleja en el proceso hijo (y viceversa), a menos
que la memoria sea compartida entre los procesos de forma explícita.

Esto, sin embargo, no significa que la memoria física sea realmente duplicada;
en general todos los sistemas operativos modernos (como \href{http://www.kernel.org/}{Linux}) utilizan una
técnica llamada \emph{COW} (de \emph{copy-on-write} en inglés, \emph{copiar-al-escribir} en
castellano) que retrasa la copia de memoria hasta que alguno de los dos
procesos escribe en un segmento. Recién en ese momento el sistema operativo
realiza la copia de \textbf{ese segmento solamente}. Es por esto que la operación
puede ser muy eficiente, y la copia de memoria es proporcional a la cantidad
de cambios que hayan.

\emph{\texttt{fork(2)}} tiene otra propiedad importante de mencionar: detiene todos
los hilos de ejecución en el proceso hijo. Es decir, el proceso hijo se crea
con un solo hilo (el hilo que ejecutó la operación de \emph{\texttt{fork(2)}}).


\subsubsection{Algoritmo}

Lo que propone el algoritmo es muy sencillo, utilizar la llamada al sistema
\emph{\texttt{fork(2)}} para crear una \emph{fotografía} de la memoria del proceso en un
nuevo proceso. En el proceso padre sigue corriendo el \emph{mutator} y en el
proceso hijo se corre la fase de marcado. El \emph{mutator} puede modificar el
grafo de conectividad pero los cambios quedan aislados del hijo (el marcado),
que tiene una visión consistente e inmutable de la memoria. El sistema
operativo duplica las páginas que modifica el padre bajo demanda, por lo tanto
la cantidad de memoria física realmente copiada es proporcional a la cantidad
y dispersión de los cambios que haga el \emph{mutator}.

La corrección del algoritmo se mantiene gracias a que la siguiente invariante
se preserva:
\begin{quote}

Cuando una celda se convierte en basura, permanece como basura hasta ser
reciclada por el recolector.
\end{quote}

Es decir, el \emph{mutator} no puede \emph{resucitar} una celda \emph{muerta} y esta
invariante se mantiene al correr la fase de marcado sobre una vista inmutable
de la memoria. El único efecto introducido es que el algoritmo toma una
aproximación más conservativa; una celda que pasó a estar \emph{muerta} luego de
que se inicie la fase de marcado, pero antes de que termine, puede no ser
reciclada hasta la próxima recolección, dado que este algoritmo no incluye una
comunicación entre \emph{mutator} y recolector para notificar cambios en el grafo
de conectividad. Pero esto no afecta la corrección del algoritmo, ya que un
recolector es correcto cuando nunca recicla celdas \emph{vivas}.

La única comunicación necesaria entre el \emph{mutator} y el recolector son los
bits de marcado (ver \hyperlink{dgc-impl}{\emph{Detalles de implementación}}), dado que la fase de barrido debe correr
en el proceso padre. No es necesario ningún tipo de sincronización entre
\emph{mutator} y recolector más allá de que uno espera a que el otro finalice.

Además de almacenar el conjunto de bits \code{mark} en memoria compartida entre
el proceso padre e hijo (necesario para la fase de barrido), las
modificaciones necesarias para hacer la fase de marcado concurrente son las
siguientes \footnote{
Se omite el manejo de errores y la activación/desactivación
del marcado concurrente a través de opciones del recolector para facilitar
la comprensión del algoritmo y los cambios realizados. Si devuelve con
error la llamada a \code{fork()} o \code{waitpid()}, se vuelve al esquema
\emph{stop-the-world} como si se hubiera desactivado el marcado concurrente
utilizando la opción del recolector \code{fork=0}.
}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{fflush}\PYG{p}{(}\PYG{n+nb}{null}\PYG{p}{)} \PYG{c+c1}{// evita que se duplique la salida de los FILE* abiertos}
   \PYG{n}{child\PYGZus{}pid} \PYG{o}{=} \PYG{n+nb}{fork}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{child\PYGZus{}pid} \PYG{k}{is} \PYG{l+m+mi}{0} \PYG{c+c1}{// proceso hijo}
      \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
      \PYG{n+nb}{exit}\PYG{p}{(}\PYG{l+m+mi}{0}\PYG{p}{)} \PYG{c+c1}{// termina el proceso hijo}
   \PYG{c+c1}{// proceso padre}
   \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{wait}\PYG{p}{(}\PYG{n}{child\PYGZus{}pid}\PYG{p}{)}
   \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{false}
   \PYG{c+c1}{// Borrado: stop\PYGZus{}the\PYGZus{}world()}
   \PYG{n}{clear\PYGZus{}mark\PYGZus{}scan\PYGZus{}bits}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}free\PYGZus{}lists}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}static\PYGZus{}data}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{push\PYGZus{}registers\PYGZus{}into\PYGZus{}stack}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{thread\PYGZus{}self}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end} \PYG{o}{=} \PYG{n+nb}{get\PYGZus{}stack\PYGZus{}top}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}stacks}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{pop\PYGZus{}registers\PYGZus{}from\PYGZus{}stack}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}user\PYGZus{}roots}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}heap}\PYG{p}{(}\PYG{p}{)}
   \PYG{c+c1}{// Borrado: start\PYGZus{}the\PYGZus{}world()}
\end{Verbatim}

Como se puede observar, el cambio es extremadamente sencillo. Sigue siendo
necesario un tiempo mínimo de pausa (básicamente el tiempo que tarda la
llamada al sistema operativo \emph{\texttt{fork(2)}}) para guardar una vista
consistente de los registros del CPU y \emph{stacks} de los hilos. Si bien el
conjunto de bits \code{mark} es compartido por el proceso padre e hijo dado que
es necesario para \emph{comunicar} las fases de marcado y barrido, cabe notar que
nunca son utilizados de forma concurrente (la fase de barrido espera que la
fase de marcado termine antes de usar dichos bits), por lo tanto no necesitan
ningún tipo de sincronización y nunca habrá más de una recolección en proceso
debido al \emph{lock} global del recolector.

A pesar de que con estos cambios el recolector técnicamente corre de forma
concurrente, se puede apreciar que para un programa con un solo hilo el
tiempo máximo de pausa seguirá siendo muy grande, incluso más grande que antes
dado el trabajo extra que impone crear un nuevo proceso y duplicar las páginas
de memoria modificadas. Lo mismo le pasará a cualquier hilo que necesite hacer
uso del recolector mientras hay una recolección en proceso, debido al \emph{lock}
global.

Para bajar este tiempo de pausa se experimenta con dos nuevas mejoras, que se
describen a continuación, cuyo objetivo es correr la fase de marcado de forma
concurrente a \textbf{todos} los hilos, incluyendo el hilo que la disparó.
\hypertarget{sol-eager-alloc}{}

\subsubsection{Creación ansiosa de \emph{pools} (\emph{eager allocation})}

Esta mejora, que puede ser controlada a través de la opción \code{eager\_alloc}
(ver \hyperlink{sol-config-spec}{\emph{Especificación de opciones}}), consiste en crear un nuevo \emph{pool} cuando un
pedido de memoria no puede ser satisfecho, justo después de lanzar la
recolección. Esto permite al recolector satisfacer la petición de memoria
inmediatamente, corriendo la fase de marcado de forma realmente concurrente,
incluso para programas con un solo hilo o programas cuyos hilos usan
frecuentemente servicios del recolector. El precio a pagar es un mayor uso de
memoria de forma temporal (y el trabajo extra de crear y eliminar \emph{pools} más
frecuentemente), pero es esperable que el tiempo máximo de pausa \textbf{real} se
vea drásticamente disminuido.

A simple vista las modificaciones necesarias para su implementación parecieran
ser las siguientes:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{c+c1}{// Agregado}
\PYG{k}{global} \PYG{n}{mark\PYGZus{}pid} \PYG{o}{=} \PYG{l+m+mi}{0}

\PYG{c+c1}{// Agregado}
\PYG{k}{function} \PYG{n}{mark\PYGZus{}is\PYGZus{}running}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{return} \PYG{k}{global} \PYG{n}{mark\PYGZus{}pid} \PYG{o}{!}\PYG{o}{=} \PYG{l+m+mi}{0}

\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{if} \PYG{n}{mark\PYGZus{}is\PYGZus{}running}\PYG{p}{(}\PYG{p}{)}                      \PYG{c+c1}{//}
      \PYG{n}{finished} \PYG{o}{=} \PYG{n+nb}{try\PYGZus{}wait}\PYG{p}{(}\PYG{k}{global} \PYG{n}{mark\PYGZus{}pid}\PYG{p}{)}   \PYG{c+c1}{//}
      \PYG{k}{if} \PYG{n}{finished}                            \PYG{c+c1}{// Agregado}
         \PYG{n}{mark\PYGZus{}pid} \PYG{o}{=} \PYG{l+m+mi}{0}                        \PYG{c+c1}{//}
         \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)}                             \PYG{c+c1}{//}
      \PYG{k}{return}                                 \PYG{c+c1}{//}
   \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{fflush}\PYG{p}{(}\PYG{n+nb}{null}\PYG{p}{)}
   \PYG{n}{child\PYGZus{}pid} \PYG{o}{=} \PYG{n+nb}{fork}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{child\PYGZus{}pid} \PYG{k}{is} \PYG{l+m+mi}{0} \PYG{c+c1}{// proceso hijo}
      \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
      \PYG{n+nb}{exit}\PYG{p}{(}\PYG{l+m+mi}{0}\PYG{p}{)}
   \PYG{c+c1}{// proceso padre}
   \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{c+c1}{// Borrado: wait(child\PYGZus{}pid)}
   \PYG{k}{global} \PYG{n}{mark\PYGZus{}pid} \PYG{o}{=} \PYG{n}{child\PYGZus{}pid}
\end{Verbatim}

Sin embargo con sólo estas modificaciones el algoritmo deja de ser correcto,
ya que tres cosas problemáticas pueden suceder:
\begin{enumerate}
\item {} 
Puede llamarse a la función \code{minimize()} mientras hay una fase de marcado
corriendo en paralelo. Esto puede provocar que se libere un \emph{pool} mientras
se lo está usando en la fase de marcado, lo que no sería un problema
(porque el proceso de marcado tiene una copia) si no fuera porque los bits
de marcado, que son compartidos por los procesos, se liberan con el \emph{pool}.

\item {} 
Si un bloque libre es asignado después de que la fase de marcado comienza,
pero antes de que termine, ese bloque será barrido dado la función
\code{rebuild\_free\_lists()} puede reciclar páginas si todos sus bloques tienen
el bit \code{freebits} activo (ver \hyperlink{dgc-algo-sweep}{\emph{Fase de barrido}}).

\item {} 
El \emph{pool} creado ansiosamente, tendrá sus bits de marcado sin activar, por
lo que en la fase de barrido será interpretado como memoria libre, incluso
cuando puedan estar siendo utilizados por el \emph{mutator}.

\end{enumerate}

El punto 1 sencillamente hace que el programa finalice con una violación de
segmento (en el mejor caso) y 2 y 3 pueden desembocar en la liberación de una
celda alcanzable por el \emph{mutator}.

El punto 1 se resuelve a través de la siguiente modificación:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{minimize}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{if} \PYG{n}{mark\PYGZus{}is\PYGZus{}running}\PYG{p}{(}\PYG{p}{)}                            \PYG{c+c1}{// Agregado}
      \PYG{k}{return}                                       \PYG{c+c1}{//}
   \PYG{n}{for} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{n}{all\PYGZus{}free} \PYG{o}{=} \PYG{n+nb}{true}
      \PYG{n}{for} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{k}{not} \PYG{n}{FREE}
            \PYG{n}{all\PYGZus{}free} \PYG{o}{=} \PYG{n+nb}{false}
            \PYG{k}{break}
      \PYG{k}{if} \PYG{n}{all\PYGZus{}free} \PYG{k}{is} \PYG{n+nb}{true}
         \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages}\PYG{p}{)}
         \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
         \PYG{n}{heap}\PYG{p}{.}\PYG{n}{remove}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
\end{Verbatim}

La resolución del punto 2 es un poco más laboriosa, ya que hay que mantener
actualizado los \code{freebits}, de forma que las celdas asignadas después de
empezar la fase de marcado no sean barridas por tener ese bit activo:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{new\PYGZus{}big}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{n}{ceil}\PYG{p}{(}\PYG{n}{size} \PYG{o}{/} \PYG{n}{PAGE\PYGZus{}SIZE}\PYG{p}{)}
   \PYG{n}{pages} \PYG{o}{=} \PYG{n}{find\PYGZus{}pages}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{pages} \PYG{o}{=} \PYG{n}{find\PYGZus{}pages}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
         \PYG{n}{minimize}\PYG{p}{(}\PYG{p}{)}
         \PYG{n}{pool} \PYG{o}{=} \PYG{n}{new\PYGZus{}pool}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
         \PYG{k}{if} \PYG{n}{pool} \PYG{k}{is} \PYG{n+nb}{null}
            \PYG{k}{return} \PYG{n+nb}{null}
         \PYG{n}{pages} \PYG{o}{=} \PYG{n}{assign\PYGZus{}pages}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}\PYG{p}{.}\PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}                         \PYG{c+c1}{// Agregado}
   \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{PAGE}
   \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mi}{1} \PYG{p}{.}\PYG{p}{.} \PYG{n}{end}\PYG{p}{]}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{CONTINUATION}
   \PYG{k}{return} \PYG{n}{pages}\PYG{p}{[}\PYG{l+m+mi}{0}\PYG{p}{]}

\PYG{k}{function} \PYG{n}{assign\PYGZus{}page}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{if} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{FREE}
            \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{block\PYGZus{}size}
            \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
               \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}                         \PYG{c+c1}{// Agregado}
               \PYG{n}{free\PYGZus{}lists}\PYG{p}{[}\PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size}\PYG{p}{]}\PYG{p}{.}\PYG{n}{link}\PYG{p}{(}\PYG{n}{block}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{global} \PYG{n}{more\PYGZus{}to\PYGZus{}scan} \PYG{o}{=} \PYG{n+nb}{false}
   \PYG{c+c1}{// Borrado: clear\PYGZus{}mark\PYGZus{}scan\PYGZus{}bits()}
   \PYG{c+c1}{// Borrado: mark\PYGZus{}free\PYGZus{}lists()}
   \PYG{n}{clear\PYGZus{}scan\PYGZus{}bits}\PYG{p}{(}\PYG{p}{)}                         \PYG{c+c1}{// Agregado}
   \PYG{n}{mark\PYGZus{}free}\PYG{p}{(}\PYG{p}{)}                               \PYG{c+c1}{//}
   \PYG{n}{mark\PYGZus{}static\PYGZus{}data}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{push\PYGZus{}registers\PYGZus{}into\PYGZus{}stack}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{thread\PYGZus{}self}\PYG{p}{.}\PYG{n}{stack}\PYG{p}{.}\PYG{n}{end} \PYG{o}{=} \PYG{n+nb}{get\PYGZus{}stack\PYGZus{}top}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}stacks}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{pop\PYGZus{}registers\PYGZus{}from\PYGZus{}stack}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}user\PYGZus{}roots}\PYG{p}{(}\PYG{p}{)}
   \PYG{n}{mark\PYGZus{}heap}\PYG{p}{(}\PYG{p}{)}

\PYG{c+c1}{// Agregado}
\PYG{k}{function} \PYG{n}{clear\PYGZus{}scan\PYGZus{}bits}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{c+c1}{// La implementación real limpia los bits en bloques de forma eficiente}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{scan} \PYG{o}{=} \PYG{n+nb}{false}

\PYG{c+c1}{// Agregado}
\PYG{k}{function} \PYG{n}{mark\PYGZus{}free}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{c+c1}{// La implementación real copia los bits en bloques de forma eficiente}
   \PYG{k}{foreach} \PYG{n}{pool} \PYG{k}{in} \PYG{n}{heap}
      \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
         \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}
            \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n}{block}\PYG{p}{.}\PYG{n}{free}

\PYG{k}{function} \PYG{n}{free\PYGZus{}big\PYGZus{}object}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{,} \PYG{n}{page}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pool\PYGZus{}end} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{o}{+} \PYG{p}{(}\PYG{n}{PAGE\PYGZus{}SIZE} \PYG{o}{*} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}pages}\PYG{p}{)}
   \PYG{k}{do}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{FREE}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}                 \PYG{c+c1}{// Agregado}
      \PYG{n}{page} \PYG{o}{=} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{byte}\PYG{o}{*}\PYG{p}{)} \PYG{n}{page} \PYG{o}{+} \PYG{n}{PAGE\PYGZus{}SIZE}
   \PYG{k}{while} \PYG{n}{page} \PYG{o}{\textless{}} \PYG{n}{pool\PYGZus{}end} \PYG{k}{and} \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{k}{is} \PYG{n}{CONTINUATION}

\PYG{k}{function} \PYG{n}{new}\PYG{p}{(}\PYG{n}{size}\PYG{p}{,} \PYG{n}{attrs}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{find\PYGZus{}block\PYGZus{}size}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}} \PYG{n}{PAGE}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{new\PYGZus{}small}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
   \PYG{k}{else}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{new\PYGZus{}big}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{throw} \PYG{n}{out\PYGZus{}of\PYGZus{}memory}
   \PYG{k}{if} \PYG{n}{final} \PYG{k}{in} \PYG{n}{attrs}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{final} \PYG{o}{=} \PYG{n+nb}{true}
   \PYG{k}{if} \PYG{n}{noscan} \PYG{k}{in} \PYG{n}{attrs}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{o}{=} \PYG{n+nb}{true}
   \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{false}         \PYG{c+c1}{// Agregado}
   \PYG{k}{return} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{void}\PYG{o}{*}\PYG{p}{)} \PYG{n}{block}

\PYG{n}{funciones} \PYG{n}{new\PYGZus{}pool}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{l+m+mi}{1}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pool} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{.}\PYG{n}{sizeof}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pool} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{n}{pool}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}
   \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{*} \PYG{n}{PAGE\PYGZus{}SIZE}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{n}{heap}\PYG{p}{.}\PYG{n}{add}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
   \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{FREE}
      \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}      \PYG{c+c1}{//}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{free} \PYG{o}{=} \PYG{n+nb}{true}       \PYG{c+c1}{// Agregado}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{true}       \PYG{c+c1}{//}
   \PYG{k}{return} \PYG{n}{pool}
\end{Verbatim}

Finalmente, el punto número 3 puede ser solucionado con el siguiente pequeño
cambio:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{n}{funciones} \PYG{n}{new\PYGZus{}pool}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{l+m+mi}{1}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{pool} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{.}\PYG{n}{sizeof}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pool} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{n}{pool}\PYG{p}{.}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{=} \PYG{n}{number\PYGZus{}of\PYGZus{}pages}
   \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{o}{=} \PYG{n}{alloc}\PYG{p}{(}\PYG{n}{number\PYGZus{}of\PYGZus{}pages} \PYG{o}{*} \PYG{n}{PAGE\PYGZus{}SIZE}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{pool}\PYG{p}{.}\PYG{n}{pages} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{n}{free}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
      \PYG{k}{return} \PYG{n+nb}{null}
   \PYG{n}{heap}\PYG{p}{.}\PYG{n}{add}\PYG{p}{(}\PYG{n}{pool}\PYG{p}{)}
   \PYG{k}{foreach} \PYG{n}{page} \PYG{k}{in} \PYG{n}{pool}
      \PYG{n}{page}\PYG{p}{.}\PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{FREE}
      \PYG{k}{foreach} \PYG{n}{block} \PYG{k}{in} \PYG{n}{page}      \PYG{c+c1}{// Agregado}
         \PYG{n}{block}\PYG{p}{.}\PYG{n}{mark} \PYG{o}{=} \PYG{n+nb}{true}       \PYG{c+c1}{//}
   \PYG{k}{return} \PYG{n}{pool}
\end{Verbatim}

La solución es conservativa porque, por un lado evita la liberación de \emph{pools}
mientras haya una recolección en curso (lo que puede hacer que el consumo de
memoria sea un poco mayor al requerido) y por otro asegura que, como se
mencionó anteriormente, los cambios hechos al grafo de conectividad luego de
iniciar la fase de marcado y antes de que ésta termine, no serán detectados
por el recolector hasta la próxima recolección (marcar todos los bloques de
un nuevo \emph{pool} como el bit \code{mark} asegura que que la memoria no sea
recolectada por la fase de barrido cuando termine el marcado).

Estas modificaciones son las que hacen que el algoritmo siga siendo correcto,
asegurando que no se van a liberar celdas \emph{vivas} (a expensas de diferir la
liberación de algunas celdas \emph{muertas} por un tiempo).
\hypertarget{sol-early-collect}{}

\subsubsection{Recolección temprana (\emph{early collection})}

Esta mejora, que puede ser controlada a través de la opción \code{early\_collect}
(ver \hyperlink{sol-config-spec}{\emph{Especificación de opciones}}), consiste en lanzar una recolección preventiva,
antes de que una petición de memoria falle. El momento en que se lanza la
recolección es controlado por la opción \code{min\_free} (ver \hyperlink{sol-ocup}{\emph{Mejora del factor de ocupación del heap}}).

De esta forma también puede correr de forma realmente concurrente el \emph{mutator}
y el recolector, al menos hasta que se acabe la memoria, en cuyo caso, a menos
que la opción \code{eager\_alloc} también esté activada (ver
\hyperlink{sol-eager-alloc}{\emph{Creación ansiosa de pools (eager allocation)}}), se deberá esperar a que la fase de marcado termine
para recuperar memoria en la fase de barrido.

Para facilitar la comprensión de esta mejora se muestran sólo los cambios
necesarios si no se utiliza la opción \code{eager\_alloc}:

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{n}{early} \PYG{o}{=} \PYG{n+nb}{false}\PYG{p}{)} \PYG{k}{is}  \PYG{c+c1}{// Modificado}
   \PYG{k}{if} \PYG{n}{mark\PYGZus{}is\PYGZus{}running}\PYG{p}{(}\PYG{p}{)}
      \PYG{n}{finished} \PYG{o}{=} \PYG{n+nb}{try\PYGZus{}wait}\PYG{p}{(}\PYG{k}{global} \PYG{n}{mark\PYGZus{}pid}\PYG{p}{)}
      \PYG{k}{if} \PYG{n}{finished}
         \PYG{n}{mark\PYGZus{}pid} \PYG{o}{=} \PYG{l+m+mi}{0}
         \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)}
         \PYG{k}{return}                     \PYG{c+c1}{//}
      \PYG{k}{else} \PYG{k}{if} \PYG{n}{early}                 \PYG{c+c1}{// Agregado}
         \PYG{k}{return}                     \PYG{c+c1}{//}
   \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{fflush}\PYG{p}{(}\PYG{n+nb}{null}\PYG{p}{)}
   \PYG{n}{child\PYGZus{}pid} \PYG{o}{=} \PYG{n+nb}{fork}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{child\PYGZus{}pid} \PYG{k}{is} \PYG{l+m+mi}{0} \PYG{c+c1}{// proceso hijo}
      \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
      \PYG{n+nb}{exit}\PYG{p}{(}\PYG{l+m+mi}{0}\PYG{p}{)}
   \PYG{c+c1}{// proceso padre}
   \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{early}                         \PYG{c+c1}{//}
      \PYG{k}{global} \PYG{n}{mark\PYGZus{}pid} \PYG{o}{=} \PYG{n}{child\PYGZus{}pid}   \PYG{c+c1}{//}
   \PYG{k}{else}                             \PYG{c+c1}{// Agregado}
      \PYG{n+nb}{wait}\PYG{p}{(}\PYG{n}{child\PYGZus{}pid}\PYG{p}{)}               \PYG{c+c1}{//}
      \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)}                       \PYG{c+c1}{//}

\PYG{c+c1}{// Agregado}
\PYG{k}{function} \PYG{n}{early\PYGZus{}collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{k}{if} \PYG{k}{not} \PYG{n}{collect\PYGZus{}in\PYGZus{}progress}\PYG{p}{(}\PYG{p}{)} \PYG{k}{and} \PYG{p}{(}\PYG{n}{percent\PYGZus{}free} \PYG{o}{\textless{}} \PYG{n}{min\PYGZus{}free}\PYG{p}{)}
      \PYG{n}{collect}\PYG{p}{(}\PYG{n+nb}{true}\PYG{p}{)}

\PYG{k}{function} \PYG{n}{new}\PYG{p}{(}\PYG{n}{size}\PYG{p}{,} \PYG{n}{attrs}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{block\PYGZus{}size} \PYG{o}{=} \PYG{n}{find\PYGZus{}block\PYGZus{}size}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block\PYGZus{}size} \PYG{o}{\textless{}} \PYG{n}{PAGE}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{new\PYGZus{}small}\PYG{p}{(}\PYG{n}{block\PYGZus{}size}\PYG{p}{)}
   \PYG{k}{else}
      \PYG{n}{block} \PYG{o}{=} \PYG{n}{new\PYGZus{}big}\PYG{p}{(}\PYG{n}{size}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{block} \PYG{k}{is} \PYG{n+nb}{null}
      \PYG{k}{throw} \PYG{n}{out\PYGZus{}of\PYGZus{}memory}
   \PYG{k}{if} \PYG{n}{final} \PYG{k}{in} \PYG{n}{attrs}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{final} \PYG{o}{=} \PYG{n+nb}{true}
   \PYG{k}{if} \PYG{n}{noscan} \PYG{k}{in} \PYG{n}{attrs}
      \PYG{n}{block}\PYG{p}{.}\PYG{n}{noscan} \PYG{o}{=} \PYG{n+nb}{true}
   \PYG{n}{early\PYGZus{}collect}\PYG{p}{(}\PYG{p}{)}               \PYG{c+c1}{// Agregado}
   \PYG{k}{return} \PYG{k}{cast}\PYG{p}{(}\PYG{n+nb}{void}\PYG{o}{*}\PYG{p}{)} \PYG{n}{block}
\end{Verbatim}

Es de esperarse que cuando no está activa la opción \code{eager\_alloc} por un
lado el tiempo de pausa máximo no sea tan chico como cuando sí lo está (dado
que si la recolección no se lanza de forma suficientemente temprana se va
a tener que esperar que la fase de marcado termine), y por otro que se hagan
más recolecciones de lo necesario (cuando pasa lo contrario, se recolecta más
temprano de lo que se debería). Sin embargo, también es de esperarse que el
consumo de memoria sea un poco menor que al usar la opción \code{eager\_alloc}.

En cuanto a la corrección del algoritmo, éste solamente presenta los problemas
número 1 y 2 mencionados en \hyperlink{sol-eager-alloc}{\emph{Creación ansiosa de pools (eager allocation)}}, dado que jamás se crean
nuevos \emph{pools} y la solución es la ya presentada, por lo tanto el algoritmo
sigue siendo correcto con los cuidados pertinentes.


\section{Resultados}

Los resultados de las modificación propuestas en la sección anterior (ver
\hyperlink{sol-mod}{\emph{Modificaciones propuestas}}) se evalúan utilizando el conjunto de pruebas mencionado en la
sección \hyperlink{sol-bench}{\emph{Banco de pruebas}}).

En esta sección se describe la forma en la que el conjunto de pruebas es
utilizado, la forma en la que se ejecutan los programas para recolectar dichos
resultados y las métricas principales utilizadas para analizarlos.

A fines prácticos, y haciendo alusión al nombre utilizado por \href{http://www.dsource.org/projects/tango}{Tango}, en esta
sección se utiliza el nombre \textbf{TBGC} (acrónimo para el nombre en inglés
\emph{Tango Basic Garbage Collector}) para hacer referencia al recolector original
provisto por \href{http://www.dsource.org/projects/tango}{Tango} 0.99.9 (que, recordamos, es el punto de partida de este
trabajo). Por otro lado, y destacando la principal modificación propuesta por
este trabajo, haremos referencia al recolector resultante de éste utilizando
el nombre \textbf{CDGC} (acrónimo para el nombre en inglés \emph{Concurrent D Garbage
Collector}).


\subsection{Ejecución del conjunto de pruebas}

Dado el indeterminismo inherente a los sistemas operativos de tiempo
compartido modernos, se hace un particular esfuerzo por obtener resultados lo
más estable posible.


\subsubsection{Hardware y software utilizado}

Para realizar las pruebas se utiliza el siguiente hardware:
\begin{itemize}
\item {} 
Procesador Intel(R) Core(TM)2 Quad CPU Q8400 @ 2.66GHz.

\item {} 
2GiB de memoria RAM.

\end{itemize}

El entorno de software es el siguiente:
\begin{itemize}
\item {} 
Sistema operativo \href{http://www.debian.org/}{Debian} Sid (para arquitectura \emph{amd64}).

\item {} 
\href{http://www.kernel.org/}{Linux} 2.6.35.7.

\item {} 
\href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} 1.063 modificado para proveer información de tipos al recolector (ver
\hyperlink{sol-precise}{\emph{Marcado preciso}}).

\item {} 
\emph{Runtime} \href{http://www.dsource.org/projects/tango}{Tango} 0.99.9 modificado para utilizar la información de tipos
provista por el compilador modificado.

\item {} 
\href{http://gcc.gnu.org/}{GCC} 4.4.5.

\item {} 
Embedded \href{http://www.gnu.org/}{GNU} C Library 2.11.2.

\end{itemize}

Si bien el sistema operativo utiliza arquitectura \emph{amd64}, dado que \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD}
todavía no soporta 64 bits, se compila y corren los programas de \href{http://www.digitalmars.com/d/}{D} en 32
bits.


\subsubsection{Opciones del compilador}

Los programas del conjunto de pruebas se compilan utilizando las siguientes
opciones del compilador \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD}:
\begin{description}
\item[{\code{-O}}] \leavevmode\\
Aplica optimizaciones generales.

\item[{\code{-inline}}] \leavevmode\\
Aplica la optimización de expansión de funciones. Consiste en sustituir la
llamada a función por el cuerpo de la función (en general solo para
funciones pequeñas).

\item[{\code{-release}}] \leavevmode\\
No genera el código para verificar pre y post-condiciones, invariantes de
representación, operaciones fuera de los límites de un arreglo y
\emph{assert}s en general (ver \hyperlink{d-dbc}{\emph{Programación confiable}}).

\end{description}


\subsubsection{Parámetros de los programas}

Los programas de prueba se ejecutan siempre con los mismos parámetros (a menos
que se especifique lo contrario), que se detallan a continuación.
\begin{description}
\item[{\code{conalloc}}] \leavevmode\\
\code{40 4 bible.txt}

Procesa 40 veces un archivo de texto plano (de 4MiB de tamaño) \footnote{
El archivo contiene la Biblia completa, la versión traducida al
inglés autorizada por el Rey Jaime o Jacobo (\emph{Authorized King James
Version} en inglés). Obtenida de: \href{http://download.o-bible.com:8080/kjv.gz}{http://download.o-bible.com:8080/kjv.gz}
}
utilizando 4 hilos (más el principal).

\item[{\code{concpu}}] \leavevmode\\
\code{40 4 bible.txt}

Procesa 40 veces un archivo de texto plano (de 4MiB de tamaño) utilizando
4 hilos (más el principal).

\item[{\code{split}}] \leavevmode\\
\code{bible.txt 2}

Procesa dos veces un archivo de texto plano (de 4MiB de tamaño).

\item[{\code{sbtree}}] \leavevmode\\
\code{16}

Construye árboles con profundidad máxima 16.

\item[{\code{bh}}] \leavevmode\\
\code{-b 4000}

Computa las interacciones gravitatorias entre 4.000 cuerpos.

\item[{\code{bisort}}] \leavevmode\\
\code{-s 2097151}

Ordena alrededor de 2 millones de números (exactamente $2^{21}
= 2097151$).

\item[{\code{em3d}}] \leavevmode\\
\code{-n 4000 -d 300 -i 74}

Realiza 74 iteraciones para modelar 4.000 nodos con grado 300.

\item[{\code{tsp}}] \leavevmode\\
\code{-c 1000000}

Resuelve el problema del viajante a través de una heurística para un
millón de ciudades.

\item[{\code{voronoi}}] \leavevmode\\
\code{-n 30000}

Se construye un diagrama con 30.000 nodos.

\item[{\code{dil}}] \leavevmode\\
\code{ddoc \$dst\_dir -hl -{-}kandil -version=Tango -version=TangoDoc
-version=Posix -version=linux \$tango\_files}

Genera la documentación de todo el código fuente de \href{http://www.dsource.org/projects/tango}{Tango} 0.99.9, donde
\code{\$dst\_dir} es el directorio donde almacenar los archivos generados
y \code{\$tango\_files} es la lista de archivos fuente de \href{http://www.dsource.org/projects/tango}{Tango}.

\end{description}

El resto de los programas se ejecutan sin parámetros (ver \hyperlink{sol-bench}{\emph{Banco de pruebas}}
para una descripción detallada sobre cada uno).


\subsubsection{Recolectores y configuraciones utilizadas}

En general se presentan resultados para TBGC y varias configuraciones de CDGC,
de manera de poder tener una mejor noción de que mejoras y problemas puede
introducir cada una de las modificaciones más importantes.

CDGC se utiliza con siguientes configuraciones:
\begin{description}
\item[{cons}] \leavevmode\\
En modo conservativo. Específicamente, utilizando el juego de opciones:

\begin{Verbatim}[commandchars=\\\{\}]
conservative=1:fork=0:early\PYGZus{}collect=0:eager\PYGZus{}alloc=0
\end{Verbatim}

\item[{prec}] \leavevmode\\
En modo preciso (ver \hyperlink{sol-precise}{\emph{Marcado preciso}}). Específicamente, utilizando el
juego de opciones:

\begin{Verbatim}[commandchars=\\\{\}]
conservative=0:fork=0:early\PYGZus{}collect=0:eager\PYGZus{}alloc=0
\end{Verbatim}

\item[{fork}] \leavevmode\\
En modo preciso activando el marcado concurrente (ver \hyperlink{sol-fork}{\emph{Marcado concurrente}}).
Específicamente, utilizando el juego de opciones:

\begin{Verbatim}[commandchars=\\\{\}]
conservative=0:fork=1:early\PYGZus{}collect=0:eager\PYGZus{}alloc=0
\end{Verbatim}

\item[{ecol}] \leavevmode\\
En modo preciso activando el marcado concurrente con recolección temprana
(ver \hyperlink{sol-early-collect}{\emph{Recolección temprana (early collection)}}).  Específicamente, utilizando el juego de
opciones:

\begin{Verbatim}[commandchars=\\\{\}]
conservative=0:fork=1:early\PYGZus{}collect=1:eager\PYGZus{}alloc=0
\end{Verbatim}

\item[{eall}] \leavevmode\\
En modo preciso activando el marcado concurrente con creación ansiosa de
\emph{pools} (ver \hyperlink{sol-eager-alloc}{\emph{Creación ansiosa de pools (eager allocation)}}).  Específicamente, utilizando el juego
de opciones:

\begin{Verbatim}[commandchars=\\\{\}]
conservative=0:fork=1:early\PYGZus{}collect=0:eager\PYGZus{}alloc=1
\end{Verbatim}

\item[{todo}] \leavevmode\\
En modo preciso activando el marcado concurrente con recolección temprana
y creación ansiosa de \emph{pools}.  Específicamente, utilizando el juego de
opciones:

\begin{Verbatim}[commandchars=\\\{\}]
conservative=0:fork=1:early\PYGZus{}collect=1:eager\PYGZus{}alloc=1
\end{Verbatim}

\end{description}


\subsubsection{Métricas utilizadas}

Para analizar los resultados se utilizan varias métricas. Las más importantes
son:
\begin{itemize}
\item {} 
Tiempo total de ejecución.

\item {} 
Tiempo máximo de \emph{stop-the-world}.

\item {} 
Tiempo máximo de pausa real.

\item {} 
Cantidad máxima de memoria utilizada.

\item {} 
Cantidad total de recolecciones realizadas.

\end{itemize}

El tiempo total de ejecución es una buena medida del \textbf{rendimiento} general
del recolector, mientras que la cantidad total de recolecciones realizadas
suele ser una buena medida de su \textbf{eficacia} \footnote{
Esto no es necesariamente cierto para recolectores con
particiones (ver \hyperlink{gc-part}{\emph{Recolección por particiones / generacional}}) o incrementales (ver \hyperlink{gc-inc}{\emph{Recolección incremental}}), dado
que en ese caso podría realizar muchas recolecciones pero cada una muy
velozmente.
}.

Los tiempos máximos de pausa, \emph{stop-the-world} y real, son una buena medida de
la \textbf{latencia} del recolector; el segundo siendo una medida más realista dado
que es raro que los demás hilos no utilicen servicios del recolector mientras
hay una recolección en curso. Esta medida es particularmente importante para
programas que necesiten algún nivel de ejecución en \emph{tiempo-real}.

En general el consumo de tiempo y espacio es un compromiso, cuando se consume
menos tiempo se necesita más espacio y viceversa. La cantidad máxima de
memoria utilizada nos da un parámetro de esta relación.


\subsubsection{Métodología de medición}

Para medir el tiempo total de ejecución se utiliza el comando
\emph{\texttt{time(1)}} con la especificación de formato \code{\%e}, siendo la medición
más realista porque incluye el tiempo de carga del ejecutable, inicialización
del \emph{runtime} de \href{http://www.digitalmars.com/d/}{D} y del recolector.

Todas las demás métricas se obtienen utilizando la salida generada por la
opción \code{collect\_stats\_file} (ver \hyperlink{sol-stats}{\emph{Recolección de estadísticas}}), por lo que no pueden ser
medidos para TBGC. Sin embargo se espera que para esos casos los resultados no
sean muy distintos a CDGC utilizando la configuración \textbf{cons} (ver sección
anterior).

Cabe destacar que las corridas para medir el tiempo total de ejecución no son
las mismas que al utilizar la opción \code{collect\_stats\_file}; cuando se mide el
tiempo de ejecución no se utiliza esa opción porque impone un trabajo extra
importante y perturbaría demasiado la medición del tiempo. Sin embargo, los
tiempos medidos internamente al utilizar la opción \code{collect\_stats\_file} son
muy precisos, dado que se hace un particular esfuerzo para que no se haga un
trabajo extra mientras se está midiendo el tiempo.

Al obtener el tiempo de \emph{stop-the-world} se ignoran los apariciones del valor
\code{-1}, que indica que se solicitó una recolección pero que ya había otra en
curso, por lo que no se pausan los hilos realmente. Como tiempo de pausa real
(ver \hyperlink{sol-fork}{\emph{Marcado concurrente}} para más detalles sobre la diferencia con el tiempo de
\emph{stop-the-world}) se toma el valor del tiempo que llevó la asignación de
memoria que disparó la recolección.

Para medir la cantidad de memoria máxima se calcula el valor máximo de la
sumatoria de: memoria usada, memoria libre, memoria desperdiciada y memoria
usada por el mismo recolector (es decir, el total de memoria pedida por el
programa al sistema operativo, aunque no toda este siendo utilizada por el
\emph{mutator} realmente).

Por último, la cantidad total de recolecciones realizadas se calcula contando
la cantidad de entradas del archivo generado por \code{collect\_stats\_file},
ignorando la cabecera y las filas cuyo valor de tiempo de \emph{stop-the-world} es
\code{-1}, debido a que en ese caso no se disparó realmente una recolección dado
que ya había una en curso.

Además, ciertas pruebas se corren variando la cantidad de procesadores
utilizados, para medir el impacto de la concurrencia en ambientes con un
procesador solo y con múltiples procesadores. Para esto se utiliza el comando
\emph{\texttt{taskset(1)}}, que establece la \emph{afinidad} de un proceso, \emph{atándolo}
a correr en un cierto conjunto de procesadores. Si bien las pruebas se
realizan utilizando 1, 2, 3 y 4 procesadores, los resultados presentados en
general se limitan a 1 y 4 procesadores, ya que no se observan diferencias
sustanciales al utilizar 2 o 3 procesadores con respecto a usar 4 (solamente
se ven de forma más atenuadas las diferencias entre la utilización de
1 o 4 procesadores). Dado que de por sí ya son muchos los datos a procesar
y analizar, agregar más resultados que no aportan información valiosa termina
resultando contraproducente.

En los casos donde se utilizan otro tipo de métricas para evaluar aspectos
particulares sobre alguna modificación se describe como se realiza la medición
donde se utiliza la métrica especial.
\begin{table}[btp]
\centering
\subfloat[Del tiempo total de ejecución.]{
\begin{tabulary}{\textwidth}{|L|L|L|L|}
\hline
\textbf{
Programa
} & \textbf{
Normal
} & \textbf{
\code{-R}
} & \textbf{
\code{-L}
}\\
\hline

bh
 & 
0.185
 & 
0.004
 & 
0.020
\\

bigarr
 & 
0.012
 & 
0.002
 & 
0.016
\\

bisort
 & 
0.006
 & 
0.003
 & 
0.006
\\

conalloc
 & 
0.004
 & 
0.004
 & 
0.004
\\

concpu
 & 
0.272
 & 
0.291
 & 
0.256
\\

dil
 & 
0.198
 & 
0.128
 & 
0.199
\\

em3d
 & 
0.006
 & 
0.033
 & 
0.029
\\

mcore
 & 
0.009
 & 
0.009
 & 
0.014
\\

rnddata
 & 
0.015
 & 
0.002
 & 
0.011
\\

sbtree
 & 
0.012
 & 
0.002
 & 
0.012
\\

split
 & 
0.025
 & 
0.000
 & 
0.004
\\

tsp
 & 
0.071
 & 
0.068
 & 
0.703
\\

voronoi
 & 
0.886
 & 
0.003
 & 
0.006
\\
\hline
\end{tabulary}

}
\hspace{0.1in}
\subfloat[Del consumo máximo de memoria.]{
\begin{tabulary}{\textwidth}{|L|L|L|L|}
\hline
\textbf{
Programa
} & \textbf{
Normal
} & \textbf{
\code{-R}
} & \textbf{
\code{-L}
}\\
\hline

bh
 & 
0.001
 & 
0.000
 & 
0.001
\\

bigarr
 & 
0.001
 & 
0.000
 & 
0.001
\\

bisort
 & 
0.000
 & 
0.000
 & 
0.000
\\

conalloc
 & 
0.753
 & 
0.000
 & 
0.001
\\

concpu
 & 
0.002
 & 
0.000
 & 
0.001
\\

dil
 & 
0.055
 & 
0.028
 & 
0.013
\\

em3d
 & 
0.000
 & 
0.001
 & 
0.001
\\

mcore
 & 
0.447
 & 
0.482
 & 
0.460
\\

rnddata
 & 
0.000
 & 
0.000
 & 
0.000
\\

sbtree
 & 
0.000
 & 
0.000
 & 
0.000
\\

split
 & 
0.000
 & 
0.000
 & 
0.000
\\

tsp
 & 
0.000
 & 
0.001
 & 
0.000
\\

voronoi
 & 
0.001
 & 
0.000
 & 
0.000
\\
\hline
\end{tabulary}

}
\caption[Variación entre corridas para TBGC]{Variación entre corridas para TBGC. La medición está efectuada utilizando
los valores máximo, mínimo y media estadística de 20 corridas, utilizando
la siguiente métrica: $\frac{max - min}{\mu}$. La medida podría
realizarse utilizando el desvío estándar en vez de la amplitud máxima, pero
en este cuadro se quiere ilustrar la variación máxima, no la típica.}
\label{t:sol-setarch}
\end{table}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-bigarr-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-bigarr-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-bigarr-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-bigarr-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-bigarr-1cpu.pdf}
}
\caption[Resultados para \code{bigarr} (utilizando 1 procesador)]{Resultados para \code{bigarr} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-bigarr-1cpu}
\end{figure}



\subsubsection{Variabilidad de los resultados entre ejecuciones}

Es de esperarse que haya una cierta variación en los resultados entre
corridas, dada la indeterminación inherente a los sistemas operativos de
tiempo compartido, que compiten por los recursos de la computadora.

Para minimizar esta variación se utilizan varias herramientas. En primer
lugar, se corren las pruebas estableciendo máxima prioridad (-19 en \href{http://www.kernel.org/}{Linux}) al
proceso utilizando el comando \emph{\texttt{nice(1)}}. La variación en la
frecuencia del reloj los procesadores (para ahorrar energía) puede ser otra
fuente de variación, por lo que se usa el comando \emph{\texttt{cpufreq-set(1)}}
para establecer la máxima frecuencia disponible de manera fija. El acceso
a disco, en las pruebas que utilizan archivos, puede ser otro factor
importante, por lo tanto se utiliza \emph{\texttt{ionice(1)}} para darle prioridad
de entrada/salida de tiempo real al proceso y se realizan las pruebas con el
caché de disco en \emph{caliente}.

Sin embargo, a pesar de tomar estas precauciones, se sigue observando una
amplia variabilidad entre corridas. Además se observa una variación más
importante de la esperada no solo en el tiempo, también en el consumo de
memoria, lo que es más extraño. Esta variación se debe principalmente a que
\href{http://www.kernel.org/}{Linux} asigna el espacio de direcciones a los procesos con una componente
azarosa (por razones de seguridad). Además, por omisión, la llamada al sistema
\emph{\texttt{mmap(2)}} asigna direcciones de memoria altas primero, entregando
direcciones más bajas en llamadas subsiguientes \hyperlink{lwn90311}{{[}LWN90311{]}}.

El comando \emph{\texttt{setarch(8)}} sirve para controlar éste y otros aspectos de
\href{http://www.kernel.org/}{Linux}. La opción \code{-L} hace que se utilice un esquema de asignación de
direcciones antiguo, que no tiene una componente aleatoria y asigna primero
direcciones bajas. La opción \code{-R} solamente desactiva la componente azarosa
al momento de asignar direcciones.

Ambas opciones, reducen notablemente la variación en los resultados (ver
cuadro \vref{t:sol-setarch}). Esto probablemente se debe a la naturaleza
conservativa del recolector, dado que la probabilidad de tener \emph{falsos
positivos} depende directamente de los valores de las direcciones de memoria,
aunque las pruebas en la que hay concurrencia involucrada, se siguen viendo
grandes variaciones, que probablemente estén vinculadas a problemas de
sincronización que se ven expuestos gracias al indeterminismo inherente a los
programas multi-hilo.

Si bien se obtienen resultados más estables utilizando un esquema diferente al
utilizado por omisión, se decide no hacerlo dado que las mediciones serían
menos realistas. Los usuarios en general no usan esta opción y se presentaría
una visión más acotada sobre el comportamiento de los programas. Sin embargo,
para evaluar el este efecto en los resultados, siempre que sea posible se
analizan los resultados de un gran número de corridas observando
principalmente su mínima, media, máxima y desvío estándar.


\subsection{Resultados para pruebas sintizadas}

A continuación se presentan los resultados obtenidos para las pruebas
sintetizadas (ver \hyperlink{sol-bench-synth}{\emph{Pruebas sintetizadas}}). Se recuerda que este conjunto de
resultados es útil para analizar ciertos aspectos puntuales de las
modificaciones propuestas, pero en general distan mucho de como se comporta un
programa real, por lo que los resultados deben ser analizados teniendo esto
presente.


\subsubsection{\texttt{bigarr}}

En la figura \vref{fig:sol-bigarr-1cpu} se pueden observar los resultados
para \code{bigarr} al utilizar un solo procesador. En ella se puede notar que el
tiempo total de ejecución en general aumenta al utilizar CDGC, esto es
esperable, dado esta prueba se limitan a usar servicios del recolector. Dado
que esta ejecución utiliza solo un procesador y por lo tanto no se puede sacar
provecho a la concurrencia, es de esperarse que el trabajo extra realizado por
las modificaciones se vea reflejado en los resultados. En la
\vref{fig:sol-bigarr-4cpu} (resultados al utilizar 4 procesadores) se puede
observar como al usar solamente \emph{eager allocation} se recupera un poco el
tiempo de ejecución, probablemente debido al incremento en la concurrencia
(aunque no se observa el mismo efecto al usar \emph{early collection}).

Observando el tiempo total de ejecución, no se esperaba un incremento tan
notorio al pasar de TBGC a una configuración equivalente de CDGC \textbf{cons},
haciendo un breve análisis de las posibles causas, lo más probable parece ser
el incremento en la complejidad de la fase de marcado dada capacidad para
marcar de forma precisa (aunque no se use la opción, se paga el precio de la
complejidad extra y sin obtener los beneficios).  Además se puede observar
como el agregado de precisión al marcado mejora un poco las cosas (donde sí se
obtiene rédito de la complejidad extra en el marcado).
\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-bigarr-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-bigarr-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-bigarr-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-bigarr-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-bigarr-4cpu.pdf}
}
\caption[Resultados para \code{bigarr} (utilizando 4 procesadores)]{Resultados para \code{bigarr} (utilizando 4 procesadores). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-bigarr-4cpu}
\end{figure}


En general se observa que al usar \emph{eager allocation} el consumo de memoria
y los tiempos de pausa se disparan mientras que la cantidad de recolecciones
disminuye drásticamente. Lo que se observa es que el programa es
más veloz pidiendo memoria que recolectándola, por lo que crece mucho el
consumo de memoria. Como consecuencia la fase de barrido (que no corre en
paralelo al \emph{mutator} como la fase de marcado) empieza a ser predominante en
el tiempo de pausa por ser tan grande la cantidad de memoria a barrer. Este
efecto se ve tanto al usar 1 como 4 procesadores, aunque el efecto es mucho
más nocivo al usar 1 debido a la alta variabilidad que impone la competencia
entre el \emph{mutator} y recolector al correr de forma concurrente.

Sin embargo, el tiempo de \emph{stop-the-world} es siempre considerablemente más
pequeño al utilizar marcado concurrente en CDGC, incluso cuando se utiliza
\emph{eager allocation}, aunque en este caso aumenta un poco, también debido al
incremento en el consumo de memoria, ya que el sistema operativo tiene que
copiar tablas de memoria más grandes al efectuar el \emph{fork} (ver
\hyperlink{sol-fork}{\emph{Marcado concurrente}}).
\clearpage\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-concpu-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-concpu-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-concpu-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-concpu-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-concpu-1cpu.pdf}
}
\caption[Resultados para \code{concpu} (utilizando 1 procesador)]{Resultados para \code{concpu} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-concpu-1cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-concpu-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-concpu-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-concpu-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-concpu-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-concpu-4cpu.pdf}
}
\caption[Resultados para \code{concpu} (utilizando 4 procesadores)]{Resultados para \code{concpu} (utilizando 4 procesadores). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-concpu-4cpu}
\end{figure}



\subsubsection{\texttt{concpu}}

En la figura \vref{fig:sol-concpu-1cpu} se pueden observar los resultados
para \code{concpu} al utilizar un solo procesador. En ella se aprecia que el
tiempo total de ejecución disminuye levemente al usar marcado concurrente
mientras no se utilice \emph{eager allocation} (si se utiliza vuelve a aumentar,
incluso más que sin marcado concurrente).

Con respecto a la cantidad de recolecciones, uso máximo de memoria y tiempo de
\emph{stop-the-world} se ve un efecto similar al descripto para \code{bigarr} (aunque
magnificado), pero sorprendentemente el tiempo total de pausa se dispara,
además con una variabilidad sorprendente, cuando se usa marcado concurrente
(pero no \emph{eager allocation}). Una posible explicación podría ser que al
realizarse el \emph{fork}, el sistema operativo muy probablemente entregue el
control del único procesador disponible al resto de los hilos que compiten por
él, por lo que queda mucho tiempo pausado en esa operación aunque realmente no
esté haciendo trabajo alguno (simplemente no tiene tiempo de procesador para
correr). Este efecto se cancela al usar \emph{eager allocation} dado que el
\emph{mutator} nunca se bloquea esperando que el proceso de marcado finalice.

Además se observa una caída importante en la cantidad de recolecciones al
utilizar marcado concurrente. Esto probablemente se deba a que solo un hilo
pide memoria (y por lo tanto dispara recolecciones), mientras los demás hilos
también estén corriendo. Al pausarse todos los hilos por menos tiempo, el
trabajo se hace más rápido (lo que explica la disminución del tiempo total de
ejecución) y son necesarias menos recolecciones, por terminar más rápido
también el hilo que las dispara.

En la \vref{fig:sol-concpu-4cpu} se pueden ver los resultados al utilizar
4 procesadores, donde el panorama cambia sustancialmente. El efecto mencionado
en el párrafo anterior no se observa más (pues el sistema operativo tiene más
procesadores para asignar a los hilos) pero todos los resultados se vuelven
más variables. Los tiempos de \emph{stop-the-world} y pausa real (salvo por lo
recién mencionado) crecen notablemente, al igual que su variación. No se
encuentra una razón evidente para esto; podría ser un error en la medición
dado que al utilizar todos los procesadores disponibles del \emph{hardware},
cualquier otro proceso que compita por tiempo de procesador puede afectarla
más fácilmente.

El tiempo total de ejecución crece considerablemente, como se espera, dado que
el programa aprovecha los múltiples hilos que pueden correr en paralelo en
procesadores diferentes.

Sin embargo, no se encuentra una razón clara para explicar el crecimiento
dramático en la cantidad de recolecciones solo al no usar marcado concurrente
para 4 procesadores.
\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-conalloc-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-conalloc-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-conalloc-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-conalloc-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-conalloc-1cpu.pdf}
}
\caption[Resultados para \code{conalloc} (utilizando 1 procesador)]{Resultados para \code{conalloc} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-conalloc-1cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-conalloc-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-conalloc-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-conalloc-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-conalloc-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-conalloc-4cpu.pdf}
}
\caption[Resultados para \code{conalloc} (utilizando 4 procesadores)]{Resultados para \code{conalloc} (utilizando 4 procesadores). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-conalloc-4cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-split-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-split-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-split-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-split-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-split-1cpu.pdf}
}
\caption[Resultados para \code{split} (utilizando 1 procesador)]{Resultados para \code{split} (utilizando 1 procesador). Se presenta el mínimos
(en negro), la media centrada entre dos desvíos estándar (en gris), y el
máximo (en blanco) calculados sobre 50 corridas (para tiempo de ejecución)
o 20 corridas (para el resto).}
\label{fig:sol-split-1cpu}
\end{figure}



\subsubsection{\texttt{conalloc}}

En la figura \vref{fig:sol-conalloc-1cpu} se pueden observar los resultados
para \code{conalloc} al utilizar un solo procesador. Los cambios con respecto
a lo observado para \code{concpu} son mínimos. El efecto de la mejoría al usar
marcado concurrente pero no \emph{eager allocation} no se observa más, dado que
\code{conalloc} pide memoria en todos los hilos, se crea un cuello de botella. Se
ve claramente como tampoco baja la cantidad de recolecciones hecha debido
a esto y se invierte la variabilidad entre los tiempos pico de pausa real
y \emph{stop-the-world} (sin una razón obvia, pero probablemente relacionado que
todos los hilos piden memoria).

Al utilizar 4 procesadores (figura \vref{fig:sol-conalloc-4cpu}), más allá de
las diferencias mencionadas para 1 procesador, no se observan grandes cambios
con respecto a lo observado para \code{concpu}, excepto que los tiempos de pausa
(real y \emph{stop-the-world}) son notablemente más pequeños, lo que pareciera
confirmar un error en la medición de \code{concpu}.


\subsubsection{\texttt{split}}

Este es el primer caso donde se aprecia la sustancial mejora proporcionada por
una pequeña optimización, el caché de \code{findSize()} (ver
\hyperlink{sol-minor-findsize}{\emph{Caché de Pool.findSize()}}). En la figura \vref{fig:sol-split-1cpu} se puede
observar con claridad como, para cualquier configuración de CDGC, hay una
caída notable en el tiempo total de ejecución. Sin embargo, a excepción de
cuando se utiliza \emph{eager allocation}, la cantidad de recolecciones y memoria
usada permanece igual.

La utilización de \emph{eager allocation} mejora (aunque de forma apenas
apreciable) el tiempo de ejecución, la cantidad de recolecciones baja a un
tercio y el tiempo de pausa real cae dramáticamente. Al usar marcado
concurrente ya se observa una caída determinante en el tiempo de
\emph{stop-the-world}. Todo esto sin verse afectado el uso máximo de memoria,
incluso al usar \emph{eager allocation}.

Se omiten los resultados para más de un procesador por ser prácticamente
idénticos para este análisis.
\clearpage\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-mcore-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-mcore-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-mcore-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-mcore-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-mcore-1cpu.pdf}
}
\caption[Resultados para \code{mcore} (utilizando 1 procesador)]{Resultados para \code{mcore} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-mcore-1cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-mcore-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-mcore-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-mcore-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-mcore-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-mcore-4cpu.pdf}
}
\caption[Resultados para \code{mcore} (utilizando 4 procesadores)]{Resultados para \code{mcore} (utilizando 4 procesadores). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-mcore-4cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-rnddata-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-rnddata-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-rnddata-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-rnddata-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-rnddata-1cpu.pdf}
}
\caption[Resultados para \code{rnddata} (utilizando 1 procesador)]{Resultados para \code{rnddata} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-rnddata-1cpu}
\end{figure}



\subsubsection{\texttt{mcore}}

El caso de \code{mcore} es interesante por ser, funcionalmente, una combinación
entre \code{concpu} y \code{split}, con un agregado extra: el incremento notable de
la competencia por utilizar el recolector entre los múltiples hilos.

Los efectos observados (en la figura \vref{fig:sol-mcore-1cpu} para
1 procesador y en la figura \vref{fig:sol-mcore-4cpu} para 4) confirman esto,
al ser una suma de los efectos observados para \code{concpu} y \code{split}, con el
agregado de una particularidad extra por la mencionada competencia entre
hilos. A diferencia de \code{concpu} donde el incremento de procesadores resulta
en un decremento en el tiempo total de ejecución, en este caso resulta en un
incremento, dado que se necesita mucha sincronización entre hilos, por
utilizar todos de forma intensiva los servicios del recolector (y por lo tanto
competir por su \emph{lock} global).

Otro efecto común observado es que cuando el tiempo de pausa es muy pequeño
(del orden de los milisegundos), el marcado concurrente suele incrementarlo en
vez de disminuirlo.


\subsubsection{\texttt{rnddata}}

En la figura \vref{fig:sol-rnddata-1cpu} se presentan los resultados para
\code{rnddata} utilizando 1 procesador. Una vez más estamos ante un caso en el
cual se observa claramente la mejoría gracias a una modificación en particular
principalmente. En esta caso es el marcado preciso. Se puede ver claramente
como mejora el tiempo de total de ejecución a algo más que la mitad (en
promedio, aunque se observa una anomalía donde el tiempo baja hasta más de
3 veces). Sin embargo, a menos que se utilice \emph{eager allocation} o \emph{early
collection} (que en este caso prueba ser muy efectivo), la cantidad de
recolecciones aumenta considerablemente.

La explicación puede ser hallada en el consumo de memoria, que baja unas
3 veces en promedio usando marcado preciso que además hace disminuir
drásticamente (unas 10 veces) el tiempo de pausa (real y \emph{stop-the-world}). El
tiempo de \emph{stop-the-world} disminuye unas 10 veces más al usar marcado
concurrente y el tiempo de pausa real al usar \emph{eager allocation}, pero en este
caso el consumo de memoria aumenta también bastante (aunque no tanto como
disminuye el tiempo de pausa, por lo que puede ser un precio que valga la pena
pagar si se necesitan tiempos de pausa muy pequeños).

El aumento en el variación de los tiempos de ejecución al usar marcado preciso
probablemente se debe a lo siguiente: con marcado conservativo, debe estar
sobreviviendo a las recolecciones el total de memoria pedida por el programa,
debido a \emph{falsos positivos} (por eso no se observa prácticamente variación en el
tiempo de ejecución y memoria máxima consumida); al marcar con precisión
parcial, se logra disminuir mucho la cantidad de \emph{falsos positivos}, pero el
\emph{stack} y la memoria estática, se sigue marcado de forma conservativa, por lo
tanto dependiendo de los valores (aleatorios) generados por la prueba, aumenta
o disminuye la cantidad de \emph{falsos positivos}, variando así la cantidad de
memoria consumida y el tiempo de ejecución.

No se muestran los resultados para más de un procesador por ser demasiado
similares a los obtenidos utilizando solo uno.


\subsubsection{\texttt{sbtree}}

Los resultados para \code{sbtree} son tan similares a los obtenidos con
\code{bigarr} que directamente se omiten por completo, dado que no aportan ningún
tipo de información nueva. Por un lado es esperable, dado que ambas pruebas se
limitan prácticamente a pedir memoria, la única diferencia es que una pide
objetos grandes y otra objetos pequeños, pero esta diferencia parece no
afectar la forma en la que se comportan los cambios introducidos en este
trabajo.
\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-bh-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-bh-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-bh-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-bh-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-bh-1cpu.pdf}
}
\caption[Resultados para \code{bh} (utilizando 1 procesador)]{Resultados para \code{bh} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-bh-1cpu}
\end{figure}

\clearpage

\subsection{Resultados para pruebas pequeñas}

A continuación se presentan los resultados obtenidos para las pruebas pequeñas
(ver \hyperlink{sol-bench-small}{\emph{Programas pequeños}}). Se recuerda que si bien este conjunto de pruebas
se compone de programas reales, que efectúan una tarea útil, están diseñados
para ejercitar la asignación de memoria y que no son recomendados para evaluar
el desempeño de recolectores de basura. Sin embargo se las utiliza igual por
falta de programas más realistas, por lo que hay que tomarlas como un grado de
suspicacia.


\subsubsection{\texttt{bh}}
\begin{table}[btp]
\centering

\begin{tabulary}{\textwidth}{|L|L|L|L|}
\hline
\textbf{
Memoria
} & \textbf{
Pedida (MiB)
} & \textbf{
Asignada (MiB)
} & \textbf{
Desperdicio (MiB)
}\\
\hline

Conservativo
 & 
302.54
 & 
354.56
 & 
52.02 (15\%)
\\

Preciso
 & 
302.54
 & 
472.26
 & 
169.72 (36\%)
\\
\hline
\end{tabulary}

\caption[Memoria pedida y asignada para \code{bh} según modo de marcado]{Memoria pedida y asignada para \code{bh} según modo de marcado conservativo
o preciso (acumulativo durante toda la vida del programa).}
\label{t:sol-prec-mem-bh}
\end{table}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-bisort-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-bisort-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-bisort-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-bisort-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-bisort-1cpu.pdf}
}
\caption[Resultados para \code{bisort} (utilizando 1 procesador)]{Resultados para \code{bisort} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-bisort-1cpu}
\end{figure}


En la figura \vref{fig:sol-bh-1cpu} se pueden observar los resultados
para \code{bh} al utilizar un solo procesador. Ya en una prueba un poco más
realista se puede observar el efecto positivo del marcado preciso, en especial
en la cantidad de recolecciones efectuadas (aunque no se traduzca en un menor
consumo de memoria).

Sin embargo se observa también un efecto nocivo del marcado preciso en el
consumo de memoria que intuitivamente debería disminuir, pero crece, y de
forma considerable (unas 3 veces en promedio). La razón de esta particularidad
es el incremento en el espacio necesario para almacenar objetos debido a que
el puntero a la información del tipo se guarda al final del bloque (ver
\hyperlink{sol-precise}{\emph{Marcado preciso}}). En el cuadro \vref{t:sol-prec-mem-bh} se puede observar
la cantidad de memoria pedida por el programa, la cantidad de memoria
realmente asignada por el recolector (y la memoria desperdiciada) cuando se
usa marcado conservativo y preciso. Estos valores fueron tomados usando la
opción \code{malloc\_stats\_file} (ver \hyperlink{sol-stats}{\emph{Recolección de estadísticas}}).

Más allá de esto, los resultados son muy similares a los obtenidos para
pruebas sintetizadas que se limitan a ejercitar el recolector (como \code{bigarr}
y \code{sbtree}), lo que habla de lo mucho que también lo hace este pequeño
programa.

No se muestran los resultados para más de un procesador por ser extremadamente
similares a los obtenidos utilizando solo uno.


\subsubsection{\texttt{bisort}}

La figura \vref{fig:sol-bisort-1cpu} muestra los resultados para \code{bisort}
al utilizar 1 procesador. En este caso el parecido es con los resultados para
la prueba sintetizada \code{split}, con la diferencia que el tiempo de ejecución
total prácticamente no varía entre TBGC y CDGC, ni entre las diferentes
configuraciones del último (evidentemente en este caso no se aprovecha el
caché de \code{findSize()}).

Otra diferencia notable es la considerable reducción del tiempo de pausa real
al utilizar \emph{early collection} (más de 3 veces menor en promedio comparado
a cuando se marca de forma conservativa, y más de 2 veces menor que cuando se
hace de forma precisa), lo que indica que la predicción de cuando se va
a necesitar una recolección es más efectiva que para \code{split}.

No se muestran los resultados para más de un procesador por ser extremadamente
similares a los obtenidos utilizando solo uno.
\clearpage\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-em3d-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-em3d-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-em3d-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-em3d-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-em3d-1cpu.pdf}
}
\caption[Resultados para \code{em3d} (utilizando 1 procesador)]{Resultados para \code{em3d} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-em3d-1cpu}
\end{figure}



\subsubsection{\texttt{em3d}}

Los resultados para \code{em3d} (figura \vref{fig:sol-em3d-1cpu}) son
sorprendentemente similares a los de \code{bisort}. La única diferencia es que en
este caso el marcado preciso y el uso de \emph{early collection} no parecen
ayudar; por el contrario, aumentan levemente el tiempo de pausa real.

Una vez más no se muestran los resultados para más de un procesador por ser
extremadamente similares a los obtenidos utilizando solo uno.
\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-tsp-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-tsp-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-tsp-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-tsp-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-tsp-1cpu.pdf}
}
\caption[Resultados para \code{tsp} (utilizando 1 procesador)]{Resultados para \code{tsp} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-tsp-1cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-voronoi-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-voronoi-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-voronoi-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-voronoi-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-voronoi-1cpu.pdf}
}
\caption[Resultados para \code{voronoi} (utilizando 1 procesador)]{Resultados para \code{voronoi} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-voronoi-1cpu}
\end{figure}

\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-voronoi-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-voronoi-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-voronoi-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-voronoi-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-voronoi-4cpu.pdf}
}
\caption[Resultados para \code{voronoi} (utilizando 4 procesadores)]{Resultados para \code{voronoi} (utilizando 4 procesadores). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-voronoi-4cpu}
\end{figure}



\subsubsection{\texttt{tsp}}

Los resultados para \code{tsp} (figura \vref{fig:sol-tsp-1cpu}) son
prácticamente idénticos a los de \code{bisort}. La única diferencia es que la
reducción del tiempo de pausa real es un poco menor.

Esto confirma en cierta medida la poca utilidad de este juego de pruebas para
medir el rendimiento de un recolector, dado que evidentemente, si bien todas
resuelven problemas diferentes, realizan todas el mismo tipo de trabajo.

Una vez más no se muestran los resultados para más de un procesador por ser
extremadamente similares a los obtenidos utilizando solo uno.


\subsubsection{\texttt{voronoi}}

En la figura \vref{fig:sol-voronoi-1cpu} se presentan los resultados para
\code{voronoi}, probablemente la prueba más interesante de este conjunto de
pruebas pequeñas.

Por un lado se puede observar una vez más como baja dramáticamente el tiempo
total de ejecución cuando se empieza a utilizar CDGC. Ya se ha visto que esto
es común en programas que se benefician del caché de \code{findSize()}, pero en
este caso no parece provenir toda la ganancia solo de ese cambio, dado que
para TBGC se ve una variación entre los resultados muy grande que desaparece
al cambiar a CDGC, esto no puede ser explicado por esa optimización. En
general la disminución de la variación de los resultados hemos visto que está
asociada al incremento en la precisión en el marcado, dado que los \emph{falsos
positivos} ponen una cuota de aleatoriedad importante. Pero este tampoco
parece ser el caso, ya que no se observan cambios apreciables al pasar a usar
marcado preciso.

Lo que se observa en esta oportunidad es un caso patológico de un mal factor
de ocupación del \emph{heap} (ver \hyperlink{sol-ocup}{\emph{Mejora del factor de ocupación del heap}}). Lo que muy probablemente está
sucediendo con TBGC es que luego de ejecutar una recolección, se libera muy
poco espacio, entonces luego de un par de asignaciones, es necesaria una nueva
recolección. En este caso es donde dificulta la tarea de analizar los
resultados la falta de métricas para TBGC, dado que no se pueden observar la
cantidad de recolecciones ni de consumo máximo de memoria. Sin embargo es
fácil corroborar esta teoría experimentalmente, gracias a la opción
\code{min\_free}. Utilizando la \code{min\_free=0} para emular el comportamiento de
TBGC (se recuerda que el valor por omisión es \code{min\_free=5}), se obtiene una
media de 4 segundos, mucho más parecida a lo obtenido para TBGC.

Otra particularidad de esta prueba es que al utilizar \emph{early collection} el
tiempo de pausa real aumenta notablemente al usar un procesador, mientras que
al usar 4 (ver figura \vref{fig:sol-voronoi-4cpu} disminuye levemente (además
de otros cambios en el nivel de variación, pero en general las medias no
cambian).


\subsection{Resultados para pruebas reales}
\begin{figure}[btp]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-dil-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-dil-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-dil-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-dil-1cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-dil-1cpu.pdf}
}
\caption[Resultados para \code{dil} (utilizando 1 procesador)]{Resultados para \code{dil} (utilizando 1 procesador). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-dil-1cpu}
\end{figure}


A continuación se presentan los resultados obtenidos para las pruebas reales
(ver \hyperlink{sol-bench-real}{\emph{Programas reales}}). Recordamos que solo se pudo halla un programa que
pueda ser utilizado a este fin, \href{http://code.google.com/p/dil/}{Dil}, y que el objetivo principal de este
trabajo se centra alrededor de obtener resultados positivos para este
programa, por lo que a pesar de ser una única prueba, se le presta particular
atención.


\subsubsection{\texttt{dil}}

En la figura \vref{fig:sol-dil-1cpu} se presentan los resultados para
\code{dil} al utilizar un procesador. Una vez más vemos una mejoría inmediata del
tiempo total de ejecución al pasar de TBGC a CDGC, y una vez más se debe
principalmente al mal factor de ocupación del \emph{heap} de TBGC, dado que
utilizando CDGC con la opción \code{min\_free=0} se obtiene una media del orden de
los 80 segundos, bastante más alta que el tiempo obtenido para TBGC.
\begin{figure}[t]
\centering
\subfloat[Tiempo de ejecución (seg)]{
\includegraphics{time-dil-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Cantidad de recolecciones]{
\includegraphics{ncol-dil-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Uso máximo de memoria (MiB)]{
\includegraphics{mem-dil-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[\emph{Stop-the-world} máximo (seg)]{
\includegraphics{stw-dil-4cpu.pdf}
}
\hspace{0.1in}
\subfloat[Pausa real máxima (seg)]{
\includegraphics{pause-dil-4cpu.pdf}
}
\caption[Resultados para \code{dil} (utilizando 4 procesadores)]{Resultados para \code{dil} (utilizando 4 procesadores). Se presenta el
mínimos (en negro), la media centrada entre dos desvíos estándar (en gris),
y el máximo (en blanco) calculados sobre 50 corridas (para tiempo de
ejecución) o 20 corridas (para el resto).}
\label{fig:sol-dil-4cpu}
\end{figure}


Sin embargo se observa un pequeño incremento del tiempo de ejecución al
introducir marcado preciso, y un incremento bastante más importante (de
alrededor del 30\%) en el consumo máximo de memoria. Nuevamente, como pasa con
la prueba \code{bh}, el efecto es probablemente producto del incremento en el
espacio necesario para almacenar objetos debido a que el puntero a la
información del tipo se guarda al final del bloque (ver \hyperlink{sol-precise}{\emph{Marcado preciso}}).
En el cuadro \vref{t:sol-prec-mem-dil} se puede observar la diferencia de
memoria desperdiciada entre el modo conservativo y preciso.
\begin{table}[b]
\centering

\begin{tabulary}{\textwidth}{|L|L|L|L|}
\hline
\textbf{
Memoria
} & \textbf{
Pedida (MiB)
} & \textbf{
Asignada (MiB)
} & \textbf{
Desperdicio (MiB)
}\\
\hline

Conservativo
 & 
307.48
 & 
399.94
 & 
92.46 (23\%)
\\

Preciso
 & 
307.48
 & 
460.24
 & 
152.76 (33\%)
\\
\hline
\end{tabulary}

\caption[Memoria pedida y asignada para \code{dil} según modo de marcado]{Memoria pedida y asignada para \code{dil} según modo de marcado conservativo
o preciso (acumulativo durante toda la vida del programa).}
\label{t:sol-prec-mem-dil}
\end{table}


El pequeño incremento en el tiempo total de ejecución podría estar dado por la
mayor probabilidad de tener \emph{falsos positivos} debido al incremento del tamaño
del \emph{heap}; se recuerda que el \emph{stack} y memoria estática se siguen marcado de
forma conservativa, incluso en modo preciso.

También se puede observar una gran disminución del tiempo total de ejecución
al empezar a usar \emph{eager allocation} (cerca de un 60\%, y más de un 200\%
comparado con TBGC), acompañado como es usual de una baja en la cantidad de
recolecciones realizadas (esta vez mayor, de más de 3 veces) y de una caída
drástica del tiempo de pausa real (alrededor de 40 veces más pequeño); todo
esto con un incremento marginal en el consumo total de memoria
(aproximadamente un 5\%). En este caso el uso de \emph{early collection} apenas
ayuda a bajar el tiempo de pausa real en un 20\% en promedio aproximadamente.
El tiempo de \emph{stop-the-world} cae dramáticamente al empezar a realizar la fase
de marcado de manera concurrente; es 200 veces más pequeño.

Al utilizar 4 procesadores (ver figura \vref{fig:sol-dil-4cpu}), hay algunos
pequeños cambios. El tiempo total de ejecución es reducido todavía más (un 20\%
que cuando se usa 1 procesador) cuando se utiliza \emph{eager allocation}. Además
al utilizar \emph{early collection}, hay otra pequeña ganancia de alrededor del
10\%, tanto para el tiempo total de ejecución como para el tiempo de pausa
real.
\hypertarget{sol-accept}{}

\subsection{Aceptación}

Los avances de este trabajo fueron comunicados regularmente a la comunidad de
\href{http://www.digitalmars.com/d/}{D} a través de un blog \hyperlink{lmtdgc}{{[}LMTDGC{]}} y del grupo de noticias de \href{http://www.digitalmars.com/d/}{D}. Los
comentarios hechos sobre el primero son en general positivos y denotan una
buena recepción por parte de la comunidad a las modificaciones propuestas.

Una vez agregado el marcado concurrente se hace un anuncio en el grupo de
noticias que también muestra buenos comentarios y aceptación, en particular
por parte de Sean Kelly, encargado de mantener el \emph{runtime} de \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0}, que
comienza a trabajar en adaptar el recolector con idea de tal vez incluirlo de
manera oficial en el futuro \hyperlink{nga19235}{{[}NGA19235{]}}. Poco después Sean Kelly publica una
versión preliminar de la adaptación en la lista de correos que coordina el
desarrollo del \emph{runtime} de \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0} \hyperlink{drt117}{{[}DRT117{]}}.

También se ha mostrado interés de incluirlo en \href{http://www.dsource.org/projects/tango}{Tango}, por lo que se han
publicado los cambios necesarios en el sistema de seguimiento de mejoras
y se encuentran actualmente en etapa de revisión \hyperlink{tt1997}{{[}TT1997{]}}.

\resetcurrentobjects
\hypertarget{--doc-conclusion}{}

\hypertarget{conclusion}{}\chapter{Conclusión}

Durante el desarrollo de este trabajo se introdujo al lenguaje de programación
\href{http://www.digitalmars.com/d/}{D} y a los conceptos básicos de recolección de basura. Luego se analizó el
recolector de basura actual y se señalaron sus principales falencias,
proponiendo un conjunto de modificaciones con el objeto de subsanarlas.
Para evaluar los resultados de las modificaciones se construyó un banco de
pruebas variado para poder analizar tanto aspectos particulares como el
funcionamiento de programas reales; y se establecieron métricas para
cuantificar dichos resultados.

El objetivo principal fue bajar la latencia del recolector, es decir el tiempo
máximo de pausa real, y se pudo comprobar que, salvo en casos muy
particulares, esto fue conseguido de manera contundente (con tiempos de pausa
hasta 200 veces menores que el recolector original de \href{http://www.digitalmars.com/d/}{D}). La inclusión del
marcado concurrente demostró ser una forma eficaz de atacar el problema.

La aceptación de la solución por parte de la comunidad también ha sido un
objetivo importante de este trabajo, y si bien en este sentido sigue siendo un
trabajo en progreso, la recepción ha sido ampliamente positiva por parte de la
comunidad y se espera que el resultado de este trabajo sea incorporado en el
corto plazo tanto a \href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0} a través de \href{http://www.dsource.org/projects/tango}{Tango}, como a \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0}.

Además de los objetivos principales se cumplieron otros objetivos anexos, pero
no por eso menos importantes. Para la aplicación real el tiempo total de
ejecución se ha reducido hasta casi una tercera parte, y para otras
aplicaciones pequeñas se ha reducido más de 17 veces. Estos resultados han
sido particularmente sorprendentes, siendo que la reducción del tiempo total
de ejecución no ha sido parte del objetivo principal y no se habían encontrado
referencias en la bibliografía de casos similares (por el contrario, en
general la baja de la latencia suele estar acompañada de una suba en el tiempo
total de ejecución).

Se ha podido experimentar además con el marcado preciso, otro de los problemas
del recolector más presentes en la comunidad. Los resultados obtenidos son
variados, encontrando casos donde se consigue una mejoría notoria y otros en
donde la forma de almacenar la información de tipos produce resultados poco
satisfactorios.

La mayor flexibilidad del recolector al ser configurable también ha demostrado
ser útil. Por un lado para este mismo trabajo, al permitir realizar mediciones
sobre el mismo binario utilizando diferentes configuraciones. Por otro, la
amplia gama de resultados dispares obtenidos son una buena muestra de que no
existen \emph{balas de plata}, y cada programa tiene necesidades particulares en
cuanto a recolección de basura. Por lo tanto, distintos programas pueden verse
beneficiados o perjudicados por diferentes configuraciones. Esto hace que la
posibilidad de configurar el recolector en tiempo de inicialización sea
particularmente útil.

Finalmente, algunas optimizaciones muy pequeñas demostraron ser también muy
valiosas para ciertos casos particulares, logrando reducciones en el tiempo
total de ejecución de hasta 5 veces.


\hypertarget{con-pending}{}\section{Puntos pendientes, problemas y limitaciones}

Si bien los objetivos de este trabajo han sido alcanzados con éxito, hay
varias pequeñas mejoras que han quedado pendientes y algunos problemas
y limitaciones conocidas. A continuación se describe cada una de ellos.
\begin{itemize}
\item {} 
Emisión de mensajes informativos para depuración.

Entre las herramientas de depuración que provee el recolector, no se ha
mencionado la posibilidad de emitir opcionalmente mensajes informativos para
ayudar a depurar tanto problemas en el recolector como en el programa que lo
usa. El recolector actual tiene esa posibilidad pero es configurable en
tiempo de compilación. En este trabajo se agregaron las opciones en tiempo
de inicialización \code{log\_file} y \code{verbose} con el propósito de poder
elegir un archivo en donde guardar los mensajes informativos y el nivel de
detalle de dichos mensajes respectivamente, pero finalmente nunca se
implementaron.

\item {} 
Predicción para estimar cuando lanzar una recolección temprana.

Las recolecciones se lanzan de manera temprana según la opción \code{min\_free}.
Una mejor aproximación podría ser predecir cuando se va a agotar la memoria
libre de forma adaptativa, calculando la tasa de asignación de memoria
y el tiempo total que tomó la recolección. Esta estimación se podría mejorar
guardando un historial de que tan acertada fue para recolecciones pasadas. La
predicción ideal debería ser capaz de:
\begin{itemize}
\item {} 
Evitar tiempos de pausa (es decir, que la recolección temprana termine antes
de que se agote la memoria libre).

\item {} 
No realizar recolecciones innecesarias (es decir, no lanzar recolecciones
tempranas si el programa no está pidiendo memoria a una tasa suficientemente
alta).

\end{itemize}

\item {} 
Explosión del uso de memoria con creación ansiosa de \emph{pools}.

Se ha observado que en situaciones muy particulares, al usar creación
ansiosa de \emph{pools} (o \emph{eager allocation}), el uso de memoria crece
desmesuradamente. Si bien este efecto se ve principalmente en las pruebas
sintetizadas con tal fin, algunos programas reales lo sufren también, pero
en general se puede atenuar utilizando también \emph{early collection}.
Recordemos además, que lo analizado es el consumo \textbf{máximo} de memoria, por
lo que una ráfaga de pedidos de memoria podría crear un pico, pero durante
la mayor parte del transcurso del programa el consumo de memoria podría ser
mucho menor. Queda pendiente analizar los casos puntuales con alguna métrica
más detallada sobre el progreso del uso de memoria.

También queda pendiente buscar alguna estimación de cuándo es conveniente
utilizar \emph{eager allocation} de forma adaptativa, dado que en general se ve
que cuando explota el consumo de memoria, también explota el tiempo de
pausa, lo que quita gran parte del sentido de usar \emph{eager allocation} en
primer lugar. Estimando de alguna manera cuanto va a crecer el tiempo de
pausa debido a esta opción, se podría desactivar temporalmente cuando no
haya ganancia en el tiempo de pausa para evitar esta explosión ante ráfagas
de pedidos de memoria.

\item {} 
Reestructuración y limpieza del código.

Si bien se han hecho muchas mejoras a nivel de estructura y limpieza de
código, ha quedado mucho pendiente. Todavía hay bastante repetición en el
código y se mantiene la arquitectura básica del recolector.

\item {} 
Experimentación con la llamada al sistema \emph{\texttt{clone(2)}}.

\href{http://www.kernel.org/}{Linux} implementa la llamada al sistema \emph{\texttt{fork(2)}} a través de otra de
más bajo nivel llamada \emph{\texttt{clone(2)}}. \emph{\texttt{clone(2)}} permite una
granularidad a la hora de indicar que partes del proceso deben ser copiadas al
hijo y cuales deben ser compartidas mucho mayor que \emph{\texttt{fork(2)}}. Por
ejemplo, se puede compartir toda la memoria del proceso, siendo este el
mecanismo por el cual \href{http://www.kernel.org/}{Linux} implementa los hilos. Para este trabajo podría
ser beneficioso usar \emph{\texttt{clone(2)}} para evitar copiar otro tipo de
estructuras dado que el proceso
hijo, al correr solo la fase de marcado, nunca va a interferir el \emph{mutator}.
Se podría experimentar no copiando las siguientes estructuras, por ejemplo:
\begin{description}
\item[{\code{CLONE\_FILES}}] \leavevmode\\
Tabla de descriptores de archivo.

\item[{\code{CLONE\_FS}}] \leavevmode\\
Tabla de sistemas de archivo montados.

\item[{\code{CLONE\_IO}}] \leavevmode\\
Contextos de entrada/salida.

\item[{\code{CLONE\_SIGHAND}}] \leavevmode\\
Tabla de manejadores de señales.

\end{description}

\item {} 
Uso de memoria compartida.

Al realizar marcado concurrente, si el \emph{mutator} usa memoria compartida entre
procesos que almacene punteros al \emph{heap} podría haber problemas, dado que la
fase de barrido no estaría trabajando con una \emph{fotografía} de la memoria. El
grafo de conectividad podría efectivamente cambiar mientras se corre la fase
de barrido y por lo tanto el algoritmo deja de ser correcto, existiendo la
posibilidad de que se reciclen celdas \emph{vivas}.

Dado que el usuario debe registrar cualquier puntero que no sea parte de la
memoria estática, \emph{stack} o \emph{heap} del recolector como parte del \emph{root set},
se podría agregar un parámetro extra a la función de registro que indique si
los punteros agregados residen en memoria compartida. De este modo, al momento
de hacer el \emph{\texttt{fork(2)}}, el recolector debería realizar una copia de
esos punteros mientras todos los hilos están pausados para obtener
efectivamente una \emph{fotografía} estable del \emph{root set}.

\item {} 
Condición de carrera al utilizar \emph{\texttt{fork(2)}}.

Existe una condición de carrera si se lanzan hilos usando directamente las
llamadas al sistema operativo, es decir si no se lanzan a través del soporte
de hilos de \href{http://www.digitalmars.com/d/}{D}, si el hilo lanzado utiliza archivos con \emph{buffer} de
C (\code{FILE*}). Esto se debe a la siguiente porción de código (introducida por
el marcado concurrente):

\begin{Verbatim}[commandchars=\\\{\}]
\PYG{k}{function} \PYG{n}{collect}\PYG{p}{(}\PYG{p}{)} \PYG{k}{is}
   \PYG{n}{stop\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{fflush}\PYG{p}{(}\PYG{n+nb}{null}\PYG{p}{)} \PYG{c+c1}{//    \textless{}-------------------------}
   \PYG{n}{child\PYGZus{}pid} \PYG{o}{=} \PYG{n+nb}{fork}\PYG{p}{(}\PYG{p}{)}
   \PYG{k}{if} \PYG{n}{child\PYGZus{}pid} \PYG{k}{is} \PYG{l+m+mi}{0}
      \PYG{n}{mark\PYGZus{}phase}\PYG{p}{(}\PYG{p}{)}
      \PYG{n+nb}{exit}\PYG{p}{(}\PYG{l+m+mi}{0}\PYG{p}{)}
   \PYG{c+c1}{// proceso padre}
   \PYG{n}{start\PYGZus{}the\PYGZus{}world}\PYG{p}{(}\PYG{p}{)}
   \PYG{n+nb}{wait}\PYG{p}{(}\PYG{n}{child\PYGZus{}pid}\PYG{p}{)}
   \PYG{n}{sweep}\PYG{p}{(}\PYG{p}{)}
\end{Verbatim}

La llamada a \emph{\texttt{fflush(3)}} es necesaria para evitar que los archivos
con \emph{buffer} escriban su contenido dos veces al dispositivo, ya que la llamada
a \emph{\texttt{fork(2)}} duplica el \emph{buffer}, y si bien el archivo no se usa en el
proceso con la fase de marcado, la biblioteca estándar de C escribe todos los
\emph{buffers} pendientes al terminar el proceso. Esto funciona para los hilos
registrados por \href{http://www.digitalmars.com/d/}{D} gracias a que \emph{\texttt{fflush(3)}} se llama cuando todos
los hilos están pausados, si no un hilo podría escribir al \emph{buffer} justo
después de llamar a \emph{\texttt{fflush(3)}} pero antes de llamar
a \emph{\texttt{fflush(2)}}. Es por esto que si hay hilos no registrados por \href{http://www.digitalmars.com/d/}{D} que
utilicen manejo de archivos con \emph{buffer} de C, esta condición sí se puede dar
y se pueden observar contenidos duplicados en dichos archivos.

Esta condición de carrera no tiene una solución simple, pero es de esperarse
que no sea un problema real dado que no es un escenario común. Sin embargo
eventualmente debería analizarse alguna solución más robusta.

\item {} 
Soporte de referencias débiles.

\href{http://www.dsource.org/projects/tango}{Tango} 0.99.9 incluye soporte de referencias débiles. Si bien se incorporó
el código para manejar las referencias débiles, se espera que no funcione
correctamente con CDGC (no se ha podido comprobar por la falta de programas
de prueba que lo utilicen). La razón es que el soporte de referencias
débiles de \href{http://www.dsource.org/projects/tango}{Tango} 0.99.9 se basa en la premisa de que la fase de marcado
corre con todos los hilos pausados, sin embargo al utilizar marcado
concurrente, esto no es más cierto. Parecen haber soluciones viables a este
problema pero no se han analizado en profundidad aún.

\item {} 
Pérdida de rendimiento con respecto al recolector original.

Se ha observado también que, al no utilizar algunas optimizaciones de CDGC
(como la mejora del factor de ocupación del \emph{heap}), éste puede tener un
rendimiento bastante menor a TBGC. Si bien no se ha investigado en
profundidad las causas de esta pérdida de rendimiento, se han identificado
algunos factores que podrían ser determinantes.

Por un lado, se ha observado que la mayor parte del tiempo extra que utiliza
CDGC proviene de la fase de marcado, en particular de los cambios
introducidos por el marcado preciso. Si bien se puede desactivar el marcado
preciso, la lógico en tiempo de ejecución no cambia, por lo que se paga el
precio sin obtener los beneficios. Queda pendiente analizar en más detalle
las causas de esto y posibles optimizaciones para subsanarlo.
\begin{table}[btp]
\centering

\begin{tabulary}{\textwidth}{|L|L|L|L|L|}
\hline
\textbf{
Programa
} & \textbf{
TBGC
} & \textbf{
CDGC
} & \textbf{
CDGC-TBGC
} & \textbf{
CDGC/TBGC
}\\
\hline

bh
 & 
22208
 & 
27604
 & 
5396
 & 
1.243
\\

bigarr
 & 
18820
 & 
24212
 & 
5392
 & 
1.287
\\

bisort
 & 
19836
 & 
25232
 & 
5396
 & 
1.272
\\

conalloc
 & 
25816
 & 
31208
 & 
5392
 & 
1.209
\\

concpu
 & 
25816
 & 
31208
 & 
5392
 & 
1.209
\\

dil
 & 
416900
 & 
422300
 & 
5400
 & 
1.013
\\

em3d
 & 
20988
 & 
26380
 & 
5392
 & 
1.257
\\

mcore
 & 
18564
 & 
23988
 & 
5424
 & 
1.292
\\

rnddata
 & 
188940
 & 
194332
 & 
5392
 & 
1.029
\\

sbtree
 & 
22196
 & 
27588
 & 
5392
 & 
1.243
\\

split
 & 
24312
 & 
29736
 & 
5424
 & 
1.223
\\

tree
 & 
18660
 & 
24084
 & 
5424
 & 
1.291
\\

tsp
 & 
20772
 & 
26168
 & 
5396
 & 
1.260
\\

voronoi
 & 
21184
 & 
26580
 & 
5396
 & 
1.255
\\
\hline
\end{tabulary}

\caption[Aumento del tamaño de la memoria estática (bytes)]{Aumento del tamaño de la memoria estática (bytes).}
\label{t:con-staticsize}
\end{table}


Además se ha observado un crecimiento importante en el tamaño del área de
memoria estática del programa. En el cuadro \vref{t:con-staticsize} se
puede observar dicho crecimiento para cada uno de los programas del banco de
pruebas. Esto se debe a que el recolector original está escrito de una forma
muy primitiva, usando muy pocos tipos de datos definidos por el usuario,
mientras que CDGC utiliza varias más, incluyendo algunos parametrizados. \href{http://www.digitalmars.com/d/}{D}
guarda la información de tipos en el área de memoria estática y se genera
mucha información por cada tipo. Además no separa el área de memoria
estática que debe ser utilizada como parte del \emph{root set} de la que no (no
hay necesidad de que la información de tipos sea parte del \emph{root set}). Esto
causa que por cada recolección, se tenga que visitar bastante más memoria y,
lo que es probablemente peor, que aumente la probabilidad de encontrar
\emph{falsos positivos}, dado que este área de memoria se marca siempre de forma
conservativa.

Finalmente, en el cuadro \vref{t:con-binsize} también se puede observar un
incremento en el tamaño del binario, lo que puede ser otra causa de la
pérdida de rendimiento, dado que puede afectar a la localidad de referencia
del caché, por ejemplo.
\begin{table}[btp]
\centering

\begin{tabulary}{\textwidth}{|L|L|L|L|L|}
\hline
\textbf{
Programa
} & \textbf{
TBGC
} & \textbf{
CDGC
} & \textbf{
CDGC-TBGC
} & \textbf{
CDGC/TBGC
}\\
\hline

bh
 & 
138060
 & 
159884
 & 
21824
 & 
1.158
\\

bigarr
 & 
192004
 & 
213832
 & 
21828
 & 
1.114
\\

bisort
 & 
115164
 & 
136988
 & 
21824
 & 
1.190
\\

conalloc
 & 
149848
 & 
171676
 & 
21828
 & 
1.146
\\

concpu
 & 
149848
 & 
171676
 & 
21828
 & 
1.146
\\

dil
 & 
1859208
 & 
1881028
 & 
21820
 & 
1.012
\\

em3d
 & 
116324
 & 
142248
 & 
25924
 & 
1.223
\\

mcore
 & 
105748
 & 
127576
 & 
21828
 & 
1.206
\\

rnddata
 & 
1492588
 & 
1518512
 & 
25924
 & 
1.017
\\

sbtree
 & 
129860
 & 
155784
 & 
25924
 & 
1.200
\\

split
 & 
144308
 & 
166136
 & 
21828
 & 
1.151
\\

tree
 & 
105844
 & 
127672
 & 
21828
 & 
1.206
\\

tsp
 & 
128412
 & 
150236
 & 
21824
 & 
1.170
\\

voronoi
 & 
141112
 & 
162936
 & 
21824
 & 
1.155
\\
\hline
\end{tabulary}

\caption[Aumento del tamaño del binario (bytes)]{Aumento del tamaño del binario (bytes).}
\label{t:con-binsize}
\end{table}


\end{itemize}


\section{Trabajos relacionados}

Dado que \href{http://www.digitalmars.com/d/}{D} no ha penetrado en ámbitos académicos, se ha encontrado un solo
trabajo de investigación relacionado. Sin embargo se ha encontrado otro
que si bien no es formal, ha sido de mucha importancia para el desarrollo de
esta tesis.

A continuación se describen ambos.
\begin{itemize}
\item {} 
\emph{Memory Management in the D Programming Language} \hyperlink{pan09}{{[}PAN09{]}}.

Tesis de licenciatura de Vladimir Panteleev cuya resumen traducido es el
siguiente:
\begin{quote}

Este reporte describe el estudio de las técnicas de manejo automático de
memoria, su implementación en el lenguaje de programación \href{http://www.digitalmars.com/d/}{D}, y el
trabajo para mejorar el estado del manejo de memoria.
\end{quote}

Si bien plantea pequeñas optimizaciones para el recolector de basura
(algunas utilizadas en este trabajo), se centra principalmente en el
desarrollo de Diamond, una utilidad para depuración de manejo de memoria en
\href{http://www.digitalmars.com/d/}{D}.

\item {} 
Integración de marcado preciso del \emph{heap} al recolector de basura
\hyperlink{dbz3463}{{[}DBZ3463{]}}.

Ya citado varias veces en este trabajo; fue comenzado por David Simcha
y publicado en el sistema de seguimiento de fallas de \href{http://www.digitalmars.com/d/}{D} que se limita a una
implementación a nivel biblioteca de usuario y sobre \href{http://www.digitalmars.com/d/2.0/changelog.html}{D 2.0}. Vincent Lang
(mejor conocido como \emph{wm4} en la comunidad de \href{http://www.digitalmars.com/d/}{D}) da continuidad a este
trabajo pero modificando el compilador \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} y trabajando con \href{http://www.digitalmars.com/d/1.0/changelog.html}{D 1.0}
y \href{http://www.dsource.org/projects/tango}{Tango}.

El soporte de marcado preciso presentado en este trabajo se basa en las
modificaciones hechas al compilador \href{http://www.digitalmars.com/d/2.0/dcompiler.html}{DMD} por Vincent Lang (que aún no fueron
integradas de forma oficial).

\end{itemize}


\section{Trabajos futuros}

En la sección \hyperlink{con-pending}{\emph{Puntos pendientes, problemas y limitaciones}} se mencionan varios aspectos de este trabajo
que podrían verse beneficiados por trabajos futuros, sin embargo se trata en
general de pequeñas optimizaciones o mejoras de alcance muy limitado.

A continuación se recopilan varios otros aspectos identificados durante el
desarrollo del presente trabajo, pero que requieren un nivel de análisis
y, potencialmente, de desarrollo mayor a los ya presentados en la sección
mencionada.
\begin{itemize}
\item {} 
Mejoras en la organización de memoria del recolector.

Si bien se ha mencionado en un principio la organización actual como un
aspecto positivo del recolector, varios resultados han demostrado
deficiencias importantes. El nivel de espacio desperdiciado por la división
de memoria en bloques puede ser muy significativa y la forma en la que se
almacena la información de tipos para el marcado preciso puede incluso
acentuarlo todavía más (como se demuestra en los resultados para \code{bh}
y \code{dil}).

Este problema no solo afecta al consumo de memoria, además genera un efecto
dominó por el incremento de la probabilidad de tener \emph{falsos positivos}
y perjudica al tiempo total de ejecución por empeorar la localidad de
referencia del caché y por hacer que se prolongue la recolección de basura
por tener que marcar y barrer más memoria.

Una posible alternativa es tener una lista de libres por \textbf{tipo}, cuyo
tamaño de bloque sea exactamente igual al tamaño del tipo que almacena. La
información de tipo se almacenaría entonces solo una vez y no habría
desperdicio de memoria alguno dejando de lado un posible relleno para
completar una página. Este esquema debería tener algún tipo de guarda para
programas con una cantidad exuberante de tipos de datos.

También podría ser conveniente separar los bloques marcados como \code{NO\_SCAN}
de los que sí deben ser marcados, de manera que no necesite almacenar
directamente los bits de \code{mark} , \code{scan} y \code{noscan}. También se podría
proponer algún área de memoria especial para almacenar cadenas de texto
(como un caso especial de lo anterior) por tener estas características muy
particular (largos muy variables, cambian de tamaño de forma relativamente
frecuente, etc.). Las posibilidades son enormes.

\item {} 
Mejoras en la fase de barrido.

En este trabajo todas las mejoras propuestas se encargaron de la fase de
marcado, pero mucho se pude mejorar en la fase de barrido también. Por un
lado se podría agregar barrido perezoso para disminuir aún más el tiempo de
pausa real. Se ha mostrado que en muchos casos los tiempos de pausa pueden
ser considerablemente altos debido a que la fase de barrido no se realiza en
paralelo como el marcado.

Otra forma de disminuir el tiempo de pausa real sería realizar un barrido
concurrente también. Esto no puede realizarse en otro proceso porque el
barrido es el encargado de ejecutar los \emph{finalizadores}, pero sí se podría
barrer en otro hilo y, por ejemplo, seguir utilizando \emph{eager allocation}
hasta que el barrido finalice.

\item {} 
Mejoras en la precisión del marcado.

Como se mencionó anteriormente, el área de memoria estática se marca de
forma conservativa dada la falta de información de tipos de ésta. Sin
embargo es bastante razonable pensar en que el compilador genere información
de tipos para el área de memoria estática o que al menos informe mejor al
recolector que partes deben ser consideradas parte del \emph{root set} y cuales
no. Dado que la memoria estática crece de forma considerable con el
incremento de la cantidad de tipos definidos por el usuario, ya solo esa
división puede hacer una diferencia importante; en especial considerando
como aumenta la memoria estática solamente por usar más tipos de datos en el
recolector.

También podría explorarse el agregado de precisión al \emph{stack} pero esto es
realmente muy complicado dado que la única solución que pareciera viable es
el uso de \emph{shadow stack} \hyperlink{hend02}{{[}HEND02{]}} que requiere un trabajo extra por cada
llamado a función, cosa que va en contra de la filosofía de \href{http://www.digitalmars.com/d/}{D} de pagar solo
por lo que se usa. Sin embargo podría explorarse agregar un esquema de ese
tipo como una opción del compilador, de forma que el usuario pueda decidir
si vale la pena para una aplicación particular o no.

\item {} 
Mejoras en la concurrencia.

El \emph{lock} global del recolector es otro aspecto que demostró ser
problemático. Podrían analizarse formas de minimizar la necesidad de usar
\emph{locks} o de hacerlo de forma más granular, de manera que algunas
operaciones del recolector puedan ser ejecutadas en paralelo. También se
podría experimentar con el uso de estructura de datos libres de \emph{locks}
(\emph{lock-free}).

Otra forma de minimizar la sincronización es utilizando \emph{pools} por hilo, de
manera de poder alocar memoria de forma concurrente y hasta explorar la
posibilidad de efectuar recolecciones locales a un solo hilo; aunque esto
último probablemente sea equivalente a implementar un recolector de basura
con particiones (por ejemplo generacional).

\item {} 
Recolección con movimiento.

La información de tipos provista por el trabajo hecho por Vincent Lang
\hyperlink{dbz3463}{{[}DBZ3463{]}} es suficientemente completa como para poder implementar un
recolector con movimiento. La efectividad de un recolector de estas
características en \href{http://www.digitalmars.com/d/}{D} está por comprobarse, dado que cualquier celda
apuntada por alguna palabra que debió ser marcada de forma conservativa debe
quedar inmóvil, por lo que gran parte del éxito de un recolector con
movimiento en \href{http://www.digitalmars.com/d/}{D} está supeditado a la proporción de celdas que queden
inmóviles. Sin embargo sea muy probablemente un área que valga la pena
explorar.

\end{itemize}

\resetcurrentobjects
\hypertarget{--doc-glosario}{}

\chapter*{Glosario}
\addcontentsline{toc}{chapter}{Glosario}
\begin{description}
\index{ABI}\item[{\emph{ABI}}] \leavevmode\hypertarget{term-abi}{}\\
Abreviatura en inglés de \emph{Application Binary Interface}, es la interfaz
de bajo nivel entre un programa y el sistema operativo u otro programa.

\index{abstracción bicolor}\item[{abstracción bicolor}] \leavevmode\hypertarget{term-abstraccion-bicolor}{}\\
Método para marcar todas las celdas de un grafo que sea accesibles de
forma transitiva a partir de una o más raíces que consiste en \emph{pintar}
todas las celdas de blanco inicialmente y luego, a medida que son
visitadas, pintarlas de negro. Al finalizar el proceso las celdas
accesibles están pintadas de negro y el resto de blanco. Ver
\hyperlink{gc-intro-mark}{\emph{Recorrido del grafo de conectividad}}.

\index{abstracción tricolor}\item[{abstracción tricolor}] \leavevmode\hypertarget{term-abstraccion-tricolor}{}\\
Método para marcar todas las celdas de un grafo que sea accesibles de
forma transitiva a partir de una o más raíces que consiste en \emph{pintar}
todas las celdas de blanco inicialmente y luego, a medida que son
visitadas, pintarlas de gris y finalmente, cuando todas sus \emph{hijas} son
visitadas también, de negro. Al finalizar el proceso las celdas
accesibles están pintadas de negro y el resto de blanco. Ver
\hyperlink{gc-intro-tricolor}{\emph{Abstracción tricolor}}.

\index{activation record}\item[{\emph{activation record}}] \leavevmode\hypertarget{term-activation-record}{}\\
Ver \emph{stack frame}.

\index{address space}\item[{\emph{address space}}] \leavevmode\hypertarget{term-address-space}{}\\
Conjunto de posibles direcciones de memoria asignada a un programa.
Puede ser un conjunto no contiguo o espaciado.

\index{arreglo}\item[{arreglo}] \leavevmode\hypertarget{term-arreglo}{}\\
Disposición de celdas de igual tamaño de forma consecutiva en la memoria
de manera que puedan ser fácilmente indizadas.

\index{back-end}\item[{\emph{back-end}}] \leavevmode\hypertarget{term-back-end}{}\\
Parte del compilador encargada de convertir la representación intermedia
generada por el \emph{front-end} a código de máquina.

\index{basura}\item[{\emph{basura}}] \leavevmode\hypertarget{term-basura}{}\\
Dependiendo del contexto, se refiere a una celda \emph{muerta}, un conjunto
de celdas \emph{muertas} o al conjunto completo de celdas \emph{muertas}.

\index{benchmark}\item[{\emph{benchmark}}] \leavevmode\hypertarget{term-benchmark}{}\\
Banco de pruebas utilizado para medir y comparar el rendimiento de un
programa, algoritmo o proceso en general.

\index{best-fit}\item[{\emph{best-fit}}] \leavevmode\hypertarget{term-best-fit}{}\\
Búsqueda para encontrar la región de memoria contigua libre que mejor se
ajuste al tamaño de un objeto (es decir, la región más pequeña lo
suficientemente grande como para almacenarlo).

\index{bitset}\item[{\emph{bitset}}] \leavevmode\hypertarget{term-bitset}{}\\
Ver conjunto de bits.

\index{BNF}\item[{BNF}] \leavevmode\hypertarget{term-bnf}{}\\
Notación de Backus-Naur, una meta-sintaxis usada para expresar
gramáticas libres de contexto.

\index{cache}\item[{\emph{cache}}] \leavevmode\hypertarget{term-cache}{}\\
Memoria pequeña (por ser típicamente muy costosa) pero muy veloz.

\index{celda}\item[{celda}] \leavevmode\hypertarget{term-celda}{}\\
Porción contigua de memoria destinada a almacenar un objeto o estructura
de dato particular.

\index{celda blanca}\item[{celda \emph{blanca}}] \leavevmode\hypertarget{term-celda-blanca}{}\\
En la abstracción bicolor y tricolor, son celdas que no fueron aún
visitadas por la fase de marcado.

\index{celda gris}\item[{celda \emph{gris}}] \leavevmode\hypertarget{term-celda-gris}{}\\
En la abstracción tricolor, son celdas que ya fueron visitadas por la
fase de marcado pero deben ser visitadas nuevamente (porque sus \emph{hijas}
no fueron visitadas por completo todavía o porque hubo algún cambio en
la celda).

\index{celda hija}\item[{celda \emph{hija}}] \leavevmode\hypertarget{term-celda-hija}{}\\
Celda para la cual existe una referencia desde la celda actual. Se dice
que \emph{H} es \emph{hija} de \emph{P} si \emph{P} contiene una referencia a \emph{H}.

\index{celda jóven}\item[{celda \emph{jóven}}] \leavevmode\hypertarget{term-celda-joven}{}\\
Celda que no lleva ninguna (o muy pocas) recolecciones sin ser
recolectada.

\index{celda muerta}\item[{celda \emph{muerta}}] \leavevmode\hypertarget{term-celda-muerta}{}\\
Celda de memoria que no puede ser accedida transitivamente a través del
\emph{root set}.

\index{celda negra}\item[{celda \emph{negra}}] \leavevmode\hypertarget{term-celda-negra}{}\\
En la abstracción bicolor y tricolor, son celdas que ya fueron
visitadas por completo (es decir, incluyendo sus celdas \emph{hijas}) por la
fase de marcado.

\index{celda vieja}\item[{celda \emph{vieja}}] \leavevmode\hypertarget{term-celda-vieja}{}\\
Celda que lleva varias recolecciones sin ser recolectada.

\index{celda viva}\item[{celda \emph{viva}}] \leavevmode\hypertarget{term-celda-viva}{}\\
Celda de memoria que puede ser accedida transitivamente a través del
\emph{root set}.

\index{ciclo}\item[{ciclo}] \leavevmode\hypertarget{term-ciclo}{}\\
Un conjunto de celdas que están referenciadas entre sí de forma tal que
siempre se puede llegar de una celda a sí misma a través de las
referencias.

\index{ciudadano de primera clase}\item[{ciudadano de primera clase}] \leavevmode\hypertarget{term-ciudadano-de-primera-clase}{}\\
Tipo soportado por completo por el lenguaje (por ejemplo disponen de
expresiones literales anónimas, pueden ser almacenados en variables
y estructuras de datos, tienen una identidad intrínseca, etc.).

\index{conjunto de bits}\item[{conjunto de bits}] \leavevmode\hypertarget{term-conjunto-de-bits}{}\\
Estructura de datos que sirve para almacenar un conjunto de indicadores
de forma eficiente. Generalmente se implementa utilizando una porción de
memoria donde cada bit es un indicador; si el bit está en 0 el indicador
no está presente y si está en 1, el indicador está activado. La
manipulación de los bits (individuales y en conjunto) en general se
realiza de forma eficiente utilizando máscaras.

\index{conteo de referencias}\item[{conteo de referencias}] \leavevmode\hypertarget{term-conteo-de-referencias}{}\\
Uno de los tres principales algoritmos clásicos de recolección de
basura. Ver \hyperlink{gc-rc}{\emph{Conteo de referencias}}.

\index{context-free grammar}\item[{\emph{context-free grammar}}] \leavevmode\hypertarget{term-context-free-grammar}{}\\
Gramática que no depende del contexto (es decir, de información
semántica).

\index{conversión covariante}\item[{conversión \emph{covariante}}] \leavevmode\hypertarget{term-conversion-covariante}{}\\
Conversión de tipos que preserva el orden de los tipos de más
específicos a más genéricos.

\index{copia de semi-espacio}\item[{copia de semi-espacio}] \leavevmode\hypertarget{term-copia-de-semi-espacio}{}\\
Uno de los tres principales algoritmos clásicos de recolección de
basura. Ver \hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

\index{copying collector}\item[{\emph{copying collector}}] \leavevmode\hypertarget{term-copying-collector}{}\\
Nombre alternativo para el algoritmo \emph{copia de semi-espacios}, aunque
puede referirse también a una familia más general de algoritmos con
movimiento de celdas. Ver \hyperlink{gc-copy}{\emph{Copia de semi-espacio}} y \hyperlink{gc-moving}{\emph{Movimiento de celdas}}.

\index{COW}\item[{COW}] \leavevmode\hypertarget{term-cow}{}\\
Del inglés \emph{Copy On Write} (\emph{copiar al escribir} en castellano) 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
\emph{kernel} de \href{http://www.kernel.org/}{Linux} por ejemplo, para que varias instancias de un mismo
proceso puedan compartir la memoria.

\index{CSV}\item[{CSV}] \leavevmode\hypertarget{term-csv}{}\\
Formato simple para almacenar datos en forma de tabla, separados por
comas (de ahí el nombre, en inglés \emph{Comma separated values}) en un
archivo de texto. Cada línea del archivo es interpretada como una fila
de datos relacionados, y cada valor de separado por comas como una
columna.

\index{CTFE}\item[{\emph{CTFE}}] \leavevmode\hypertarget{term-ctfe}{}\\
Abreviatura en inglés de \emph{Compile-Time Function Execution}, es la
capacidad de un lenguaje de programación de ejecutar una función en
tiempo de compilación en vez de tiempo de ejecución.

\index{dangling pointer}\item[{\emph{dangling pointer}}] \leavevmode\hypertarget{term-dangling-pointer}{}\\
Puntero que almacena una dirección de memoria inválida (\emph{puntero
colgante} en castellano).

\index{DbC}\item[{\emph{DbC}}] \leavevmode\hypertarget{term-dbc}{}\\
Ver diseño por contrato (del inglés \emph{Design by Contract}).

\index{delegado}\item[{\emph{delegado}}] \leavevmode\hypertarget{term-delegado}{}\\
Es una estructura simple que modela una función acompañada de un
contexto. En general se utiliza para representar un puntero a una
función miembro de un objeto en particular o a una función anidada
(donde el contexto es el \emph{stack frame} de la función que la contiene).

\index{desbordamiento de pila}\item[{desbordamiento de pila}] \leavevmode\hypertarget{term-desbordamiento-de-pila}{}\\
Agotamiento de la memoria del \emph{stack}.

\index{determinístico}\item[{determinístico}] \leavevmode\hypertarget{term-deterministico}{}\\
Algoritmo o proceso que se comporta de forma predecible (dada una cierta
entrada siempre produce el mismo resultado y los pasos realizados son
exactamente los mismo, pasando por la misma secuencia de estados).

\index{dirección}\item[{dirección}] \leavevmode\hypertarget{term-direccion}{}\\
Una dirección de memoria es la especificación de su ubicación en
memoria. Típicamente se representan como enteros sin signo y ocupan una
palabra.

\index{diseño por contrato}\item[{\emph{diseño por contrato}}] \leavevmode\hypertarget{term-diseno-por-contrato}{}\\
Técnica de diseño de software que consiste en especificar formalmente,
de forma precisa y verificable, la interfaz entre componentes de
software.

\index{excepción}\item[{\emph{excepción}}] \leavevmode\hypertarget{term-excepcion}{}\\
Construcción de un lenguaje de programación para manejar la presencia de
situaciones anormales (en general errores) cambiando el flujo de
ejecución del programa.

\index{exception-safe}\item[{\emph{exception-safe}}] \leavevmode\hypertarget{term-exception-safe}{}\\
Propiedad de un programa que ante un error en tiempo de ejecución
manifestado como una \emph{excepción} no provoca efectos indeseados (como
pérdida de memoria, corrupción de datos o salida inválida).

\index{falso positivo}\item[{\emph{falso positivo}}] \leavevmode\hypertarget{term-falso-positivo}{}\\
Palabra que es tratada como un potencial puntero cuyo valor almacenado
coincide con una dirección válida dentro del \emph{heap} pero que en realidad
no es un puntero.

\index{fase de barrido}\item[{fase de barrido}] \leavevmode\hypertarget{term-fase-de-barrido}{}\\
Segunda fase del algoritmo \emph{marcado y barrido}. Ver
\hyperlink{gc-mark-sweep}{\emph{Marcado y barrido}}.

\index{fase de marcado}\item[{fase de marcado}] \leavevmode\hypertarget{term-fase-de-marcado}{}\\
Primera fase del algoritmo \emph{marcado y barrido} (entre otros). Ver
\hyperlink{gc-intro-mark}{\emph{Recorrido del grafo de conectividad}} y \hyperlink{gc-mark-sweep}{\emph{Marcado y barrido}}.

\index{finalización}\item[{finalización}] \leavevmode\hypertarget{term-finalizacion}{}\\
Referente a la acción de llamar a una función miembro de un objeto,
generalmente llamada destructor, cuando éste deja de ser utilizado.

\index{first-fit}\item[{\emph{first-fit}}] \leavevmode\hypertarget{term-first-fit}{}\\
Búsqueda para encontrar la primera región de memoria contigua libre
donde quepa un objeto (es decir, la primera región lo suficientemente
grande como para almacenar el objeto a asignar).

\index{forwarding address}\item[{\emph{forwarding address}}] \leavevmode\hypertarget{term-forwarding-address}{}\\
Dirección de memoria de re-dirección utilizada para localizar la nueva
ubicación de una celda en algoritmos de recolección con movimiento. Ver
\hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

\index{fragmentación}\item[{\emph{fragmentación}}] \leavevmode\hypertarget{term-fragmentacion}{}\\
Incapacidad de usar memoria debido a la disposición de memoria
actualmente en uso, que deja la memoria libre dividida en bloques
demasiado pequeños.

\index{fromspace}\item[{\emph{fromspace}}] \leavevmode\hypertarget{term-fromspace}{}\\
Uno de los dos semi-espacios del algoritmo \emph{copia de semi-espacios}. Ver
\hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

\index{front-end}\item[{\emph{front-end}}] \leavevmode\hypertarget{term-front-end}{}\\
Parte del compilador encargada de hacer el análisis léxico, sintáctico
y semántico del código fuente, generando una representación intermedia
que luego el \emph{back-end} convierte a código de máquina.

\index{función pura}\item[{función \emph{pura}}] \leavevmode\hypertarget{term-funcion-pura}{}\\
Función que no tiene efectos secundarios. Una función pura ejecutada con
los mismo parámetros siempre devuelve el mismo resultado.

\index{grafo de conectividad}\item[{grafo de conectividad}] \leavevmode\hypertarget{term-grafo-de-conectividad}{}\\
Grafo conformado por la memoria del \emph{heap}. Los vértices son las celdas
de memoria y las aristas las referencias (o punteros) que tiene una
celda apuntando a otras. Ver \hyperlink{gc-intro-basics}{\emph{Conceptos básicos}}.

\index{heap}\item[{\emph{heap}}] \leavevmode\hypertarget{term-heap}{}\\
Área de memoria que en la cual se asigna y liberan celdas dinámicamente
(durante la ejecución del programa).

\index{hit rate}\item[{\emph{hit rate}}] \leavevmode\hypertarget{term-hit-rate}{}\\
Frecuencia con la que el caché puede responder con éxito.

\index{lista de libres}\item[{lista de libres}] \leavevmode\hypertarget{term-lista-de-libres}{}\\
Forma de organizar el \emph{heap} en la cual se asigna una nueva celda
obteniéndola de una lista de celdas libres. Ver \hyperlink{gc-free-list}{\emph{Lista de libres / pointer bump allocation}}.

\index{live set}\item[{\emph{live set}}] \leavevmode\hypertarget{term-live-set}{}\\
Conjunto de todas las celdas \emph{vivas}.

\index{localidad de referencia}\item[{localidad de referencia}] \leavevmode\hypertarget{term-localidad-de-referencia}{}\\
Medida en que los accesos sucesivos de memoria cercana espacialmente son
cercanos también en el tiempo. Por ejemplo, un programa que lee todos
los elementos de una matriz contigua de una vez o que utiliza la misma
variable repetidamente tiene buena localidad referencia.

\index{lock}\item[{\emph{lock}}] \leavevmode\hypertarget{term-lock}{}\\
También conocido como \emph{mutex} (abreviación de \emph{exclusión mutua} en
inglés), es un objeto de sincronización que permite serializar la
ejecución de múltiples hilos.

\index{low level allocator}\item[{\emph{low level allocator}}] \leavevmode\hypertarget{term-low-level-allocator}{}\\
Administrador de memoria de bajo nivel que obtiene la memoria del
sistema operativo y la provee al recolector (o al \emph{mutator}
directamente).

\index{marcado y barrido}\item[{marcado y barrido}] \leavevmode\hypertarget{term-marcado-y-barrido}{}\\
Uno de los tres principales algoritmos clásicos de recolección de
basura. Ver \hyperlink{gc-mark-sweep}{\emph{Marcado y barrido}}.

\index{memoria estática}\item[{memoria estática}] \leavevmode\hypertarget{term-memoria-estatica}{}\\
Memoria fija destinada a un programa. Es fija en el sentido en que no
varía su tamaño ni puede asignarse o liberarse durante la ejecución del
programa.

\index{mixin}\item[{\emph{mixin}}] \leavevmode\hypertarget{term-mixin}{}\\
En \href{http://www.digitalmars.com/d/}{D} se refiere a un fragmento de código (M) que puede incluirse dentro
de otro (O) como si M hubiera sido escrito directamente dentro de O. En
general se utiliza para suplantar la herencia múltiple pero tiene muchos
otros usos.

\index{multi-core}\item[{\emph{multi-core}}] \leavevmode\hypertarget{term-multi-core}{}\\
Arquitectura que combina dos o más núcleos (\emph{cores}) independientes que
trabajan a la misma frecuencia, pero dentro de un solo circuito
integrado o procesador.

\index{mutator}\item[{\emph{mutator}}] \leavevmode\hypertarget{term-mutator}{}\\
Parte del programa que realiza cambios al grafo de conectividad.

\index{overhead}\item[{\emph{overhead}}] \leavevmode\hypertarget{term-overhead}{}\\
Cualquier combinación de exceso directo o indirecto de tiempo de
computación, memoria, ancho de banda u otro recurso que sea requerido
para cumplir un objetivo particular.

\index{palabra}\item[{palabra}] \leavevmode\hypertarget{term-palabra}{}\\
Tamaño de dato característico de un procesador que permite almacenar una
dirección de memoria. Generalmente este tamaño coincide con el tamaño de
dato que el procesador puede manipular de forma más eficiente.

\index{parsing}\item[{\emph{parsing}}] \leavevmode\hypertarget{term-parsing}{}\\
Análisis sintáctico de un lenguaje estructurado.

\index{pattern matching}\item[{\emph{pattern matching}}] \leavevmode\hypertarget{term-pattern-matching}{}\\
Acto de verificar la presencia de un constituyente sintáctico de un
patrón dado.

\index{pinning}\item[{\emph{pinning}}] \leavevmode\hypertarget{term-pinning}{}\\
Técnica que consiste en marcar una celda como inmóvil. Generalmente se
utiliza en recolectores semi-conservativos con movimiento para no mover
celdas que son alcanzadas desde palabras para las que no se tiene
información de tipos.

\index{pointer bump allocation}\item[{\emph{pointer bump allocation}}] \leavevmode\hypertarget{term-pointer-bump-allocation}{}\\
Forma de organizar el \emph{heap} en la cual se asigna una nueva celda
incrementando un puntero. Ver \hyperlink{gc-free-list}{\emph{Lista de libres / pointer bump allocation}}.

\index{POSIX}\item[{POSIX}] \leavevmode\hypertarget{term-posix}{}\\
Familia de estándares de llamadas al sistema operativo definidos por la
IEEE y especificados formalmente en IEEE 1003. El nombre proviene del
acrónimo de \emph{Portable Operating System Interface}, agregando la X final
como representación de \emph{UNIX}, como seña de identidad de la API.

\index{puntero interior}\item[{puntero \emph{interior}}] \leavevmode\hypertarget{term-puntero-interior}{}\\
Puntero que en vez de apuntar al inicio de una celda, apuntan a una
dirección arbitraria dentro de ella.

\index{página}\item[{página}] \leavevmode\hypertarget{term-pagina}{}\\
Unidad mínima de memoria que asigna el sistema operativo a un programa
(típicamente el tamaño de página es de 4096 bytes).

\index{RAII}\item[{\emph{RAII}}] \leavevmode\hypertarget{term-raii}{}\\
Técnica que consiste en reservar recursos por medio de la construcción
de un objeto y liberarlos cuando éste se libera (del inglés \emph{Resourse
Adquisition Is Initialization}).

\index{recolección con movimiento de celdas}\item[{recolección con movimiento de celdas}] \leavevmode\hypertarget{term-recoleccion-con-movimiento-de-celdas}{}\\
Recolección en la cual una celda de memoria puede ser movida a otra
ubicación en el \emph{heap}. Ver \hyperlink{gc-moving}{\emph{Movimiento de celdas}}.

\index{recolección concurrente}\item[{recolección concurrente}] \leavevmode\hypertarget{term-recoleccion-concurrente}{}\\
Recolección que puede correr en paralelo con el \emph{mutator}. Ver
\hyperlink{gc-concurrent}{\emph{Recolección concurrente / paralela / stop-the-world}}.

\index{recolección conservativa}\item[{recolección conservativa}] \leavevmode\hypertarget{term-recoleccion-conservativa}{}\\
Recolección que no tiene información de tipos y trata cada palabra del
\emph{root set} o \emph{heap} como un posible puntero. Ver \hyperlink{gc-conserv}{\emph{Recolectores conservativos versus precisos}}.

\index{recolección directa}\item[{recolección directa}] \leavevmode\hypertarget{term-recoleccion-directa}{}\\
Recolección en la cual el compilador o lenguaje instrumenta al \emph{mutator}
de forma tal que la información sobre el grafo de conectividad se
mantenga activamente cada vez que hay un cambio en él. Ver
\hyperlink{gc-direct}{\emph{Recolección directa / indirecta}}.

\index{recolección generacional}\item[{recolección generacional}] \leavevmode\hypertarget{term-recoleccion-generacional}{}\\
Caso particular de \emph{recolección por particiones} en el cual las
particiones se realizan utilizando la cantidad de recolecciones que
\emph{sobrevive} una celda. Ver \hyperlink{gc-part}{\emph{Recolección por particiones / generacional}}.

\index{recolección incremental}\item[{recolección incremental}] \leavevmode\hypertarget{term-recoleccion-incremental}{}\\
Recolección que se realiza de forma intercalada con el \emph{mutator}. Ver
\hyperlink{gc-inc}{\emph{Recolección incremental}}.

\index{recolección indirecta}\item[{recolección indirecta}] \leavevmode\hypertarget{term-recoleccion-indirecta}{}\\
Recolección que, generalmente, no interfiere con el \emph{mutator} en cada
actualización del grafo de conectividad. Ver \hyperlink{gc-direct}{\emph{Recolección directa / indirecta}}.

\index{recolección paralela}\item[{recolección paralela}] \leavevmode\hypertarget{term-recoleccion-paralela}{}\\
Recolección que puede correr en paralelo en varios hilos. Ver
\hyperlink{gc-concurrent}{\emph{Recolección concurrente / paralela / stop-the-world}}.

\index{recolección por particiones}\item[{recolección por particiones}] \leavevmode\hypertarget{term-recoleccion-por-particiones}{}\\
Recolección en la que se divide el \emph{heap} en particiones con el objetivo
de recolectar la partición con mayor concentración de \emph{basura}. Ver
\hyperlink{gc-part}{\emph{Recolección por particiones / generacional}}.

\index{recolección precisa}\item[{recolección precisa}] \leavevmode\hypertarget{term-recoleccion-precisa}{}\\
Recolección que tiene información de tipos completa y puede determinar
exactamente que palabras son punteros y cuales no. Ver
\hyperlink{gc-conserv}{\emph{Recolectores conservativos versus precisos}}.

\index{recolección semi-precisa}\item[{recolección semi-precisa}] \leavevmode\hypertarget{term-recoleccion-semi-precisa}{}\\
Recolección que tiene información de tipos parcial y puede determinar
para algunas palabras si son punteros o no, y para otras las trata como
punteros potenciales. Ver \hyperlink{gc-conserv}{\emph{Recolectores conservativos versus precisos}}.

\index{recolección stop-the-world}\item[{recolección \emph{stop-the-world}}] \leavevmode\hypertarget{term-recoleccion-stop-the-world}{}\\
Recolección que detiene todos los hilos del \emph{mutator}. Ver
\hyperlink{gc-concurrent}{\emph{Recolección concurrente / paralela / stop-the-world}}.

\index{recolector}\item[{recolector}] \leavevmode\hypertarget{term-recolector}{}\\
Parte del programa que recupera celdas \emph{muertas} (no realiza cambios en
el grafo de conectividad).

\index{recolector híbrido}\item[{recolector \emph{híbrido}}] \leavevmode\hypertarget{term-recolector-hibrido}{}\\
Recolector que emplea distintas técnicas de recolección dependiendo de
distintas características de las celdas (por ejemplo cuantas
recolecciones lleva sin ser recolectado, el tamaño de celda, etc.).

\index{referencia débil}\item[{referencia débil}] \leavevmode\hypertarget{term-referencia-debil}{}\\
Referencia que no es tomada en cuenta en el grafo de conectividad (es
decir, si un objeto es solamente alcanzable a través de una referencia
débil, puede ser reciclado por el recolector).

\index{registro}\item[{registro}] \leavevmode\hypertarget{term-registro}{}\\
Memoria muy veloz del procesador que por lo general tiene el tamaño de
una palabra. En general son muy escasos y es donde los procesadores
hacen realmente los cálculos.

\index{root set}\item[{\emph{root set}}] \leavevmode\hypertarget{term-root-set}{}\\
Conjunto de celdas de memoria que sirven como punto de partida para
recorrer el grafo de conectividad. En general se compone de memoria
estática, registros y el \emph{stack}.

\index{RTTI}\item[{\emph{RTTI}}] \leavevmode\hypertarget{term-rtti}{}\\
Abreviatura del inglés \emph{Run-Time Type Identification}, es la información
de tipos disponible en tiempo de ejecución.

\index{runtime}\item[{\emph{runtime}}] \leavevmode\hypertarget{term-runtime}{}\\
Biblioteca de un lenguaje que provee los servicios básicos (como
creación de objetos, manejo de hilos u otras construcciones que ofrezca
el lenguaje).

\index{semi-space}\item[{\emph{semi-space}}] \leavevmode\hypertarget{term-semi-space}{}\\
Nombre alternativo para el algoritmo \emph{copia de semi-espacios}. Ver
\hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

\index{semántica de referencia}\item[{semántica de referencia}] \leavevmode\hypertarget{term-semantica-de-referencia}{}\\
Propiedad de los tipos que son tratados como si fueran un puntero. Nunca
se hacen copias del objeto, siempre se pasa por referencia
implícitamente.

\index{semántica de valor}\item[{semántica de valor}] \leavevmode\hypertarget{term-semantica-de-valor}{}\\
Propiedad de los tipos son tratado como si fuera un valor concreto. En
general se pasa por valor y se hacen copias a menos que se utilice
explícitamente un puntero.

\index{sistema de tipos}\item[{sistema de tipos}] \leavevmode\hypertarget{term-sistema-de-tipos}{}\\
Forma en que un lenguaje de programación clasifica valores y expresiones
en tipos, como los manipula y como interactúan éstos entre sí.

\index{slicing}\item[{\emph{slicing}}] \leavevmode\hypertarget{term-slicing}{}\\
Problema que surge cuando los objetos polimórficos tienen semántica de
valor, consiste en pasar una clase derivada a una función que acepta una
clase base por valor como parámetro. Al realizarse la copia, se utiliza
solo la parte de la clase base y se pierden (o \emph{rebanan}) los atributos
de la clase derivada, y la información de tipos en tiempo de ejecución
(\emph{RTTI}).

\index{stack}\item[{\emph{stack}}] \leavevmode\hypertarget{term-stack}{}\\
Área de memoria organizada en forma de pila donde se almacenan
típicamente las variables locales, parámetros, valor de retorno
y dirección de retorno de las subrutinas.

\index{stack frame}\item[{\emph{stack frame}}] \leavevmode\hypertarget{term-stack-frame}{}\\
Estructura de datos dependiente de la arquitectura que contiene
información del estado de una función, incluyendo, por ejemplo, sus
variables locales, parámetros y dirección de retorno.

\index{stack overflow}\item[{\emph{stack overflow}}] \leavevmode\hypertarget{term-stack-overflow}{}\\
Ver \emph{desbordamiento de pila}.

\index{stop-the-world}\item[{\emph{stop-the-world}}] \leavevmode\hypertarget{term-stop-the-world}{}\\
Ver \emph{recolección stop-the-world}.

\index{string}\item[{\emph{string}}] \leavevmode\hypertarget{term-string}{}\\
Secuencia lineal de caracteres utilizada normalmente en los lenguajes de
programación para representar texto (aunque pueden ser utilizados para
representar una secuencia lineal de bytes de cualquier tipo también).

\index{system programming}\item[{\emph{system programming}}] \leavevmode\hypertarget{term-system-programming}{}\\
Se refiere a programación de bajo nivel. En general involucra
manipulación de punteros, acceso directo al lenguaje de máquina y por
consiguiente al \emph{hardware}.

\index{templates}\item[{\emph{templates}}] \leavevmode\hypertarget{term-templates}{}\\
Técnica para construir algoritmos genéricos incluyendo parámetros como
tipos o valores.

\index{thread-safe}\item[{\emph{thread-safe}}] \leavevmode\hypertarget{term-thread-safe}{}\\
Propiedad de una función o fragmento de código que permite que corra
concurrentemente en dos o más hilos de ejecución paralelos sin provocar
efectos indeseados (como pérdida de memoria, corrupción de datos
o salida inválida).

\index{tipado dinámico}\item[{\emph{tipado} dinámico}] \leavevmode\hypertarget{term-tipado-dinamico}{}\\
Verificación de tipos en tiempo de ejecución.

\index{tipado estático}\item[{\emph{tipado} estático}] \leavevmode\hypertarget{term-tipado-estatico}{}\\
Verificación de tipos en tiempo de compilación.

\index{tospace}\item[{\emph{tospace}}] \leavevmode\hypertarget{term-tospace}{}\\
Uno de los dos semi-espacios del algoritmo \emph{copia de semi-espacios}. Ver
\hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

\index{two level allocators}\item[{\emph{two level allocators}}] \leavevmode\hypertarget{term-two-level-allocators}{}\\
Administrador de memoria que utiliza dos niveles para organizar las
celdas de memoria; obtiene del sistema operativo páginas completas
y éstas a su vez de dividen en bloques que son utilizados para almacenar
las celdas.

\index{two-space}\item[{\emph{two-space}}] \leavevmode\hypertarget{term-two-space}{}\\
Nombre alternativo para el algoritmo \emph{copia de semi-espacios}. Ver
\hyperlink{gc-copy}{\emph{Copia de semi-espacio}}.

\index{type-safe}\item[{\emph{type-safe}}] \leavevmode\hypertarget{term-type-safe}{}\\
Operación que no compromete ni subvierte la verificación de tipos.

\index{verificación de tipos}\item[{verificación de tipos}] \leavevmode\hypertarget{term-verificacion-de-tipos}{}\\
Forma en la que un sistema de tipos asigna tipos y verifica sus
interacciones.

\index{weak reference}\item[{\emph{weak reference}}] \leavevmode\hypertarget{term-weak-reference}{}\\
Ver referencia débil.

\index{working set}\item[{\emph{working set}}] \leavevmode\hypertarget{term-working-set}{}\\
Conjunto de celdas con la que trabaja el programa de forma intensiva
durante un período considerable de tiempo.

\end{description}

\begin{thebibliography}{LWN90311}

\bibitem[ALX10]{ALX10}{\hypertarget{alx10}{} Andrei Alexandrescu. The D Programming Language. Addison-WesleyProfessional, 2010. ISBN 978-0321635365.}
\bibitem[BEZO06]{BEZO06}{\hypertarget{bezo06}{} Emery D. Berger, Benjamin G. Zorn. DieHard: probabilisticmemory safety for unsafe languages. PLDI `06: Proceedings of the 2006ACM SIGPLAN conference on Programming language design andimplementation. 2006. ISBN 1-59593-320-4.}
\bibitem[BH86]{BH86}{\hypertarget{bh86}{} J. Barnes and P. Hut. A hierarchical o(N log N) force-calculationalgorithm.  Nature Volumen 324, páginas 446-449.  Diciembre 1986.}
\bibitem[BKIP08]{BKIP08}{\hypertarget{bkip08}{} Kris Macleod Bell, Lars Ivar Igesund, Sean Kelly, and MichaelParker. Learn to Tango with D. Apress, 2007. ISBN 1-59059-960-8.}
\bibitem[BLA06]{BLA06}{\hypertarget{bla06}{} Blackburn et ál. The DaCapo benchmarks: java benchmarkingdevelopment and analysis. OOPSLA `06: Proceedings of the 21st annual ACMSIGPLAN conference on Object-oriented programming systems, languages, andapplications. ISBN 1-59593-348-4.  Páginas 169-190. 2006.}
\bibitem[BLAC08]{BLAC08}{\hypertarget{blac08}{} Stephen Blackburn and Kathryn McKinley. \href{http://cs.anu.edu.au/techreports/2007/TR-CS-07-04.pdf}{Immix Garbage Collection:Mutator Locality, Fast Collection, and Space Efficiency} \footnote{\href{http://cs.anu.edu.au/techreports/2007/TR-CS-07-04.pdf}{http://cs.anu.edu.au/techreports/2007/TR-CS-07-04.pdf}}. Proceedings ofthe ACM SIGPLAN `08 Conference on Programming Language Design andImplementation. Páginas 22-32. Junio 2008.}
\bibitem[BN98]{BN98}{\hypertarget{bn98}{} G. Bilardi and A. Nicolau. Adaptive Bitonic Sorting: An optimalparallel algorithm for shared-memory machines. SIAM J. Comput.Volumen 18, número 2, páginas 216-228. 1998.}
\bibitem[BOEH88]{BOEH88}{\hypertarget{boeh88}{} Hans-Juergen Boehm and Mark Weiser. \href{http://www.hpl.hp.com/personal/Hans\_Boehm/spe\_gc\_paper/preprint.pdf}{Garbage Collection in anUncooperative Environment} \footnote{\href{http://www.hpl.hp.com/personal/Hans\_Boehm/spe\_gc\_paper/preprint.pdf}{http://www.hpl.hp.com/personal/Hans\_Boehm/spe\_gc\_paper/preprint.pdf}}. Software Practice and Experience Volumen 18,Número 9. Páginas 807-820. Septiembre 1988.}
\bibitem[BOEH91]{BOEH91}{\hypertarget{boeh91}{} Hans-Juergen Boehm and Alan J. Demers and Scott  Shenker. \href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/papers/pldi91.ps.Z}{MostlyParallel Garbage Collection} \footnote{\href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/papers/pldi91.ps.Z}{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/papers/pldi91.ps.Z}}. Proceedings of the ACM SIGPLAN `91Conference on Programming Language Design and Implementation, Volumen 26,Número 6. Páginas 157-164. Junio 1991.}
\bibitem[BOEH93]{BOEH93}{\hypertarget{boeh93}{} Hans-Juergen Boehm. \href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/papers/pldi93.ps.Z}{Space Efficient Conservative GarbageCollection} \footnote{\href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/papers/pldi93.ps.Z}{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/papers/pldi93.ps.Z}}. Proceedingsof the ACM SIGPLAN `93 Conference on Programming Language Design andImplementation, Volumen 28, Número 6. Páginas 197-206. Junio 1993.}
\bibitem[BOEHWD]{BOEHWD}{\hypertarget{boehwd}{} Hans-J. Boehm. \href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/gcdescr.html}{Conservative GC Algorithmic Overview} \footnote{\href{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/gcdescr.html}{http://www.hpl.hp.com/personal/Hans\_Boehm/gc/gcdescr.html}}. HPLabs / SGI. Obtenido en Junio de 2009.}
\bibitem[CAR95]{CAR95}{\hypertarget{car95}{} A. Rogers and M. Carlisle and J. Reppy and L. Hendren. SupportingDynamic Data Structures on Distributed Memory Machines. Transactions onProgramming Languages and Systems, volúmen 17, número 2. Marzo 1995.}
\bibitem[CDG93]{CDG93}{\hypertarget{cdg93}{} D. Culler, A. Dusseau, S. Goldstein, A. Krishnamurthy, S. Lumetta,T. von Eicken and K. Yelick. Parallel Programming in Split-C.Supercomputing 1993, páginas 262-273. 1993.}
\bibitem[CMK01]{CMK01}{\hypertarget{cmk01}{} B. Cahoon and K. S. McKinley. \href{ftp://ftp.cs.umass.edu/pub/osl/papers/pact01-prefetch.ps.gz}{Data Flow Analysis for SoftwarePrefetching Linked Data Structures in Java} \footnote{\href{ftp://ftp.cs.umass.edu/pub/osl/papers/pact01-prefetch.ps.gz}{ftp://ftp.cs.umass.edu/pub/osl/papers/pact01-prefetch.ps.gz}}. International Conference onParallel Architectures and Compilation Techniques (PACT). Barcelona,España.  Septiembre 2001.}
\bibitem[DBZ3463]{DBZ3463}{\hypertarget{dbz3463}{} David Simcha, et ál. \href{http://d.puremagic.com/issues/show\_bug.cgi?id=3463}{Integrate Precise Heap Scanning Into theGC} \footnote{\href{http://d.puremagic.com/issues/show\_bug.cgi?id=3463}{http://d.puremagic.com/issues/show\_bug.cgi?id=3463}}. The D Programming Language Issue Tracking System. Issue 3463.Noviembre 2009.}
\bibitem[DRT117]{DRT117}{\hypertarget{drt117}{} Sean Kelly. \href{http://lists.puremagic.com/pipermail/d-runtime/2010-September/000117.html}{D Concurrent GC} \footnote{\href{http://lists.puremagic.com/pipermail/d-runtime/2010-September/000117.html}{http://lists.puremagic.com/pipermail/d-runtime/2010-September/000117.html}}. Lista de correo de Druntime. 15de septiembre de 2010.}
\bibitem[DWAA]{DWAA}{\hypertarget{dwaa}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/hash-map.html}{D Programming Language 1.0 Reference, Associativearrays} \footnote{\href{http://www.digitalmars.com/d/1.0/hash-map.html}{http://www.digitalmars.com/d/1.0/hash-map.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWAB]{DWAB}{\hypertarget{dwab}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/abi.html}{D Programming Language 1.0 Reference, D ApplicationBinary Interface} \footnote{\href{http://www.digitalmars.com/d/1.0/abi.html}{http://www.digitalmars.com/d/1.0/abi.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWAL]{DWAL}{\hypertarget{dwal}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/attribute.html\#align}{D Programming Language 1.0 Reference, Alignattribute} \footnote{\href{http://www.digitalmars.com/d/1.0/attribute.html\#align}{http://www.digitalmars.com/d/1.0/attribute.html\#align}}.  Digital Mars. Octubre 2010.}
\bibitem[DWAR]{DWAR}{\hypertarget{dwar}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/arrays.html}{D Programming Language 1.0 Reference, Arrays} \footnote{\href{http://www.digitalmars.com/d/1.0/arrays.html}{http://www.digitalmars.com/d/1.0/arrays.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWCC]{DWCC}{\hypertarget{dwcc}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/interfaceToC.html}{D Programming Language 1.0 Reference, Interfacing toC} \footnote{\href{http://www.digitalmars.com/d/1.0/interfaceToC.html}{http://www.digitalmars.com/d/1.0/interfaceToC.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWCF]{DWCF}{\hypertarget{dwcf}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/function.html\#interpretation}{D Programming Language 1.0 Reference, Compile TimeFunction Execution (CTFE)} \footnote{\href{http://www.digitalmars.com/d/1.0/function.html\#interpretation}{http://www.digitalmars.com/d/1.0/function.html\#interpretation}}.  Digital Mars. Octubre 2010.}
\bibitem[DWCL]{DWCL}{\hypertarget{dwcl}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/class.html}{D Programming Language 1.0 Reference, Classes} \footnote{\href{http://www.digitalmars.com/d/1.0/class.html}{http://www.digitalmars.com/d/1.0/class.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWCP]{DWCP}{\hypertarget{dwcp}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/dbc.html}{D Programming Language 1.0 Reference, Contracts} \footnote{\href{http://www.digitalmars.com/d/1.0/dbc.html}{http://www.digitalmars.com/d/1.0/dbc.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWDC]{DWDC}{\hypertarget{dwdc}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/declaration.html}{D Programming Language 1.0 Reference,Declarations} \footnote{\href{http://www.digitalmars.com/d/1.0/declaration.html}{http://www.digitalmars.com/d/1.0/declaration.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWDE]{DWDE}{\hypertarget{dwde}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/class.html\#Destructor}{D Programming Language 1.0 Reference, Classdestructors} \footnote{\href{http://www.digitalmars.com/d/1.0/class.html\#Destructor}{http://www.digitalmars.com/d/1.0/class.html\#Destructor}}. Digital Mars. Octubre 2010.}
\bibitem[DWDO]{DWDO}{\hypertarget{dwdo}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/ddoc.html}{D Programming Language 1.0 Reference, Embeddeddocumentation} \footnote{\href{http://www.digitalmars.com/d/1.0/ddoc.html}{http://www.digitalmars.com/d/1.0/ddoc.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWEB]{DWEB}{\hypertarget{dweb}{} Walter Bright. \href{http://www.digitalmars.com/d/}{D Programming Language Website} \footnote{\href{http://www.digitalmars.com/d/}{http://www.digitalmars.com/d/}}. Digital Mars.Octubre 2010.}
\bibitem[DWES]{DWES}{\hypertarget{dwes}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/exception-safe.html}{D Programming Language 1.0 Reference, Exception safepogramming} \footnote{\href{http://www.digitalmars.com/d/1.0/exception-safe.html}{http://www.digitalmars.com/d/1.0/exception-safe.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWEX]{DWEX}{\hypertarget{dwex}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/statement.html\#TryStatement}{D Programming Language 1.0 Reference, Trystatement} \footnote{\href{http://www.digitalmars.com/d/1.0/statement.html\#TryStatement}{http://www.digitalmars.com/d/1.0/statement.html\#TryStatement}}.  Digital Mars. Octubre 2010.}
\bibitem[DWFE]{DWFE}{\hypertarget{dwfe}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/statement.html\#ForeachStatement}{D Programming Language 1.0 Reference, Foreachstatement} \footnote{\href{http://www.digitalmars.com/d/1.0/statement.html\#ForeachStatement}{http://www.digitalmars.com/d/1.0/statement.html\#ForeachStatement}}.  Digital Mars. Octubre 2010.}
\bibitem[DWFU]{DWFU}{\hypertarget{dwfu}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/function.html}{D Programming Language 1.0 Reference, Functions} \footnote{\href{http://www.digitalmars.com/d/1.0/function.html}{http://www.digitalmars.com/d/1.0/function.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWGC]{DWGC}{\hypertarget{dwgc}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/garbage.html}{D Programming Language 1.0 Reference, Garbagecollection} \footnote{\href{http://www.digitalmars.com/d/1.0/garbage.html}{http://www.digitalmars.com/d/1.0/garbage.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWGT]{DWGT}{\hypertarget{dwgt}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/statement.html\#GotoStatement}{D Programming Language 1.0 Reference, Gotostatement} \footnote{\href{http://www.digitalmars.com/d/1.0/statement.html\#GotoStatement}{http://www.digitalmars.com/d/1.0/statement.html\#GotoStatement}}.  Digital Mars. Octubre 2010.}
\bibitem[DWIA]{DWIA}{\hypertarget{dwia}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/iasm.html}{D Programming Language 1.0 Reference, D x86 InlineAssembler} \footnote{\href{http://www.digitalmars.com/d/1.0/iasm.html}{http://www.digitalmars.com/d/1.0/iasm.html}}. Digital Mars. Octubre 2010.}
\bibitem[DWIE]{DWIE}{\hypertarget{dwie}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/expression.html\#IsExpression}{D Programming Language 1.0 Reference, Isexpressions} \footnote{\href{http://www.digitalmars.com/d/1.0/expression.html\#IsExpression}{http://www.digitalmars.com/d/1.0/expression.html\#IsExpression}}.  Digital Mars. Octubre 2010.}
\bibitem[DWIF]{DWIF}{\hypertarget{dwif}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/interface.html}{D Programming Language 1.0 Reference, Interfaces} \footnote{\href{http://www.digitalmars.com/d/1.0/interface.html}{http://www.digitalmars.com/d/1.0/interface.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWIN]{DWIN}{\hypertarget{dwin}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/declaration.html\#AutoDeclaration}{D Programming Language 1.0 Reference, Autodeclaration} \footnote{\href{http://www.digitalmars.com/d/1.0/declaration.html\#AutoDeclaration}{http://www.digitalmars.com/d/1.0/declaration.html\#AutoDeclaration}}. Digital Mars. Octubre 2010.}
\bibitem[DWLR]{DWLR}{\hypertarget{dwlr}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/lex.html}{D Programming Language 1.0 Reference} \footnote{\href{http://www.digitalmars.com/d/1.0/lex.html}{http://www.digitalmars.com/d/1.0/lex.html}}. DigitalMars. Octubre 2010.}
\bibitem[DWME]{DWME}{\hypertarget{dwme}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/expression.html\#MixinExpression}{D Programming Language 1.0 Reference, Mixinexpressions} \footnote{\href{http://www.digitalmars.com/d/1.0/expression.html\#MixinExpression}{http://www.digitalmars.com/d/1.0/expression.html\#MixinExpression}}.  Digital Mars. Octubre 2010.}
\bibitem[DWMM]{DWMM}{\hypertarget{dwmm}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/memory.html}{D Programming Language 1.0 Reference, Memorymanagement} \footnote{\href{http://www.digitalmars.com/d/1.0/memory.html}{http://www.digitalmars.com/d/1.0/memory.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWMO]{DWMO}{\hypertarget{dwmo}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/module.html}{D Programming Language 1.0 Reference, Modules} \footnote{\href{http://www.digitalmars.com/d/1.0/module.html}{http://www.digitalmars.com/d/1.0/module.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWMT]{DWMT}{\hypertarget{dwmt}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/template-mixin.html}{D Programming Language 1.0 Reference, Templatemixins} \footnote{\href{http://www.digitalmars.com/d/1.0/template-mixin.html}{http://www.digitalmars.com/d/1.0/template-mixin.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWMX]{DWMX}{\hypertarget{dwmx}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/mixin.html}{D Programming Language 1.0 Reference, Mixins} \footnote{\href{http://www.digitalmars.com/d/1.0/mixin.html}{http://www.digitalmars.com/d/1.0/mixin.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWNC]{DWNC}{\hypertarget{dwnc}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/class.html\#nested}{D Programming Language 1.0 Reference, Nestedclasses} \footnote{\href{http://www.digitalmars.com/d/1.0/class.html\#nested}{http://www.digitalmars.com/d/1.0/class.html\#nested}}.  Digital Mars. Octubre 2010.}
\bibitem[DWOO]{DWOO}{\hypertarget{dwoo}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/operatoroverloading.html}{D Programming Language 1.0 Reference, Operatoroverloading} \footnote{\href{http://www.digitalmars.com/d/1.0/operatoroverloading.html}{http://www.digitalmars.com/d/1.0/operatoroverloading.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWOV]{DWOV}{\hypertarget{dwov}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/overview.html}{D Programming 1.0 Language Overview} \footnote{\href{http://www.digitalmars.com/d/1.0/overview.html}{http://www.digitalmars.com/d/1.0/overview.html}}. DigitalMars. Octubre 2010.}
\bibitem[DWPR]{DWPR}{\hypertarget{dwpr}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/property.html}{D Programming Language 1.0 Reference, Properties} \footnote{\href{http://www.digitalmars.com/d/1.0/property.html}{http://www.digitalmars.com/d/1.0/property.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWSI]{DWSI}{\hypertarget{dwsi}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/version.html\#staticif}{D Programming Language 1.0 Reference, Staticif} \footnote{\href{http://www.digitalmars.com/d/1.0/version.html\#staticif}{http://www.digitalmars.com/d/1.0/version.html\#staticif}}. Digital Mars. Octubre 2010.}
\bibitem[DWSR]{DWSR}{\hypertarget{dwsr}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/arrays.html\#strings}{D Programming Language 1.0 Reference, Strings} \footnote{\href{http://www.digitalmars.com/d/1.0/arrays.html\#strings}{http://www.digitalmars.com/d/1.0/arrays.html\#strings}}.Digital Mars. Octubre 2010.}
\bibitem[DWST]{DWST}{\hypertarget{dwst}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/struct.html}{D Programming Language 1.0 Reference, Struct\& unions} \footnote{\href{http://www.digitalmars.com/d/1.0/struct.html}{http://www.digitalmars.com/d/1.0/struct.html}}.  Digital Mars. Octubre 2010.}
\bibitem[DWSY]{DWSY}{\hypertarget{dwsy}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/statement.html\#SynchronizedStatement}{D Programming Language 1.0 Reference, Synchronizedstatement} \footnote{\href{http://www.digitalmars.com/d/1.0/statement.html\#SynchronizedStatement}{http://www.digitalmars.com/d/1.0/statement.html\#SynchronizedStatement}}.  Digital Mars. Octubre 2010.}
\bibitem[DWTO]{DWTO}{\hypertarget{dwto}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/declaration.html\#typeof}{D Programming Language 1.0 Reference, Typeof} \footnote{\href{http://www.digitalmars.com/d/1.0/declaration.html\#typeof}{http://www.digitalmars.com/d/1.0/declaration.html\#typeof}}.Digital Mars. Octubre 2010.}
\bibitem[DWTP]{DWTP}{\hypertarget{dwtp}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/template.html}{D Programming Language 1.0 Reference, Templates} \footnote{\href{http://www.digitalmars.com/d/1.0/template.html}{http://www.digitalmars.com/d/1.0/template.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWTY]{DWTY}{\hypertarget{dwty}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/type.html}{D Programming Language 1.0 Reference, Types} \footnote{\href{http://www.digitalmars.com/d/1.0/type.html}{http://www.digitalmars.com/d/1.0/type.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWUT]{DWUT}{\hypertarget{dwut}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/unittest.html}{D Programming Language 1.0 Reference, Unit tests} \footnote{\href{http://www.digitalmars.com/d/1.0/unittest.html}{http://www.digitalmars.com/d/1.0/unittest.html}}.Digital Mars. Octubre 2010.}
\bibitem[DWVI]{DWVI}{\hypertarget{dwvi}{} Walter Bright. \href{http://www.digitalmars.com/d/1.0/declaration.html\#VoidInitializer}{D Programming Language 1.0 Reference, Voidinitializations} \footnote{\href{http://www.digitalmars.com/d/1.0/declaration.html\#VoidInitializer}{http://www.digitalmars.com/d/1.0/declaration.html\#VoidInitializer}}.  Digital Mars. Octubre 2010.}
\bibitem[GCBIB]{GCBIB}{\hypertarget{gcbib}{} Richard Jones. \href{http://www.cs.ukc.ac.uk/people/staff/rej/gcbib/gcbib.html}{The Garbage Collection Bibliography} \footnote{\href{http://www.cs.ukc.ac.uk/people/staff/rej/gcbib/gcbib.html}{http://www.cs.ukc.ac.uk/people/staff/rej/gcbib/gcbib.html}}. 1996-2009.}
\bibitem[GS85]{GS85}{\hypertarget{gs85}{} L. Guibas and J. Stolfi. General Subdivisions and Voronoi Diagrams.ACM Trans. on Graphics Volumen 4, número 2, páginas 74-123. 1985.}
\bibitem[HDH03]{HDH03}{\hypertarget{hdh03}{} Martin Hirzel, Amer Diwan, and Matthew Hertz, Proceedingsof the 18th Conference on Object-Oriented Programming, Systems,Languages, and Applications (OOPSLA 2003), Anaheim, CA, Oct. 26-30,2003.}
\bibitem[HEND02]{HEND02}{\hypertarget{hend02}{} Fergus Henderson. Accurate garbage collection in an uncooperativeenvironment. Proceedings of the Third International Symposium on MemoryManagement (2002). ACM. Páginas 150-156. Febrero, 2003.}
\bibitem[HIRZ03]{HIRZ03}{\hypertarget{hirz03}{} Martin Hirzel and Amer Diwan and Matthew Hertz.\href{http://www-plan.cs.colorado.edu/diwan/cbgc.pdf}{Connectivity-based Garbage Collection} \footnote{\href{http://www-plan.cs.colorado.edu/diwan/cbgc.pdf}{http://www-plan.cs.colorado.edu/diwan/cbgc.pdf}}. Proceedings of the ACM OOPSLA`03 Conference on Object-Oriented Programming, Systems, Languages andApplications. Noviembre 2003.}
\bibitem[HUEL98]{HUEL98}{\hypertarget{huel98}{} Lorenz Huelsbergen and Phil Winterbottom. Very ConcurrentMark-\&-Sweep Garbage Collection without Fine-Grain Synchronization.Proceedings of the International Symposium on Memory Management. Páginas166-175. ACM. 1998. ISBN 1-58113-114-3.}
\bibitem[IEEE754]{IEEE754}{\hypertarget{ieee754}{} IEEE Task P754. IEEE 754-2008, Standard for Floating-PointArithmetic. IEEE. ISBN 0-7381-5753-8. 2008.}
\bibitem[JOLI96]{JOLI96}{\hypertarget{joli96}{} Richard Jones, Rafael D Lins. Garbage Collection: Algorithmsfor Automatic Dynamic Memory Management. John Wiley \& Sons, 1996.ISBN 0-471-94148-4.}
\bibitem[KAR77]{KAR77}{\hypertarget{kar77}{} R. Karp. Probabilistic analysis of partitioning algorithms for thetraveling-salesman problem in the plane.  Mathematics of OperationsResearch Volumen 2, número 3, páginas 209-224. Agosto 1977.}
\bibitem[LINS05]{LINS05}{\hypertarget{lins05}{} Rafael D Lins. A New Multi-Processor Architecture forParallel Lazy Cyclic Reference Counting. Proceedings of the 17thInternational Symposium on Computer Architecture on High PerformanceComputing - Volume 00 (páginas 35-43), 2005. IEEE Press.}
\bibitem[LMTDGC]{LMTDGC}{\hypertarget{lmtdgc}{} Leandro Lucarella. \href{http://llucax.com.ar/blog/blog/tag/dgc}{Luca's Meaninless Thoughts, tag DGC} \footnote{\href{http://llucax.com.ar/blog/blog/tag/dgc}{http://llucax.com.ar/blog/blog/tag/dgc}}.2008-2010.}
\bibitem[LWN90311]{LWN90311}{\hypertarget{lwn90311}{} Ingo Molnar. \href{http://lwn.net/Articles/90311/}{flexible-mmap-2.6.7-D5} \footnote{\href{http://lwn.net/Articles/90311/}{http://lwn.net/Articles/90311/}}. Linux Weekly News.Junio 2004.}
\bibitem[MOLA06]{MOLA06}{\hypertarget{mola06}{} Paolo Molaro. \href{http://www.go-mono.com/meeting06/mono-sgen.pdf}{A new Mono GC} \footnote{\href{http://www.go-mono.com/meeting06/mono-sgen.pdf}{http://www.go-mono.com/meeting06/mono-sgen.pdf}}. Octubre 2006.}
\bibitem[MOLAWE]{MOLAWE}{\hypertarget{molawe}{} Paolo Molaro. \href{http://www.mono-project.com/Compacting\_GC}{Compacting GC} \footnote{\href{http://www.mono-project.com/Compacting\_GC}{http://www.mono-project.com/Compacting\_GC}}. The Mono Project. Obtenido enJunio de 2009.}
\bibitem[NAS00]{NAS00}{\hypertarget{nas00}{} Neil Schemenauer. \href{http://arctrix.com/nas/python/gc/}{Garbage Collection for Python} \footnote{\href{http://arctrix.com/nas/python/gc/}{http://arctrix.com/nas/python/gc/}}. 2000.}
\bibitem[NGA15246]{NGA15246}{\hypertarget{nga15246}{} Mason Green. Blaze 2.0. Grupo de noticiasdigitalmars.D.announce, 16 de marzo de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/Blaze\_2.0\_15246.html}{Mensaje número 15246} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/Blaze\_2.0\_15246.html}{http://www.digitalmars.com/d/archives/digitalmars/D/announce/Blaze\_2.0\_15246.html}}.}
\bibitem[NGA19235]{NGA19235}{\hypertarget{nga19235}{} Leandro Lucarella. D Concurrent GC. Grupo de noticiasdigitalmars.D.announce, 9 de septiembre de 2010. \href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/D\_Concurrent\_GC\_19235.html}{Mensaje número 19235} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/D\_Concurrent\_GC\_19235.html}{http://www.digitalmars.com/d/archives/digitalmars/D/announce/D\_Concurrent\_GC\_19235.html}}.}
\bibitem[NGA6842]{NGA6842}{\hypertarget{nga6842}{} Walter Bright. Transitioning to a type aware GarbageCollector. Grupo de noticias digitalmars.D.announce, 22 de enero de2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/Transitioning\_to\_a\_type\_aware\_Garbage\_Collector\_6842.html}{Mensaje número 6842} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/Transitioning\_to\_a\_type\_aware\_Garbage\_Collector\_6842.html}{http://www.digitalmars.com/d/archives/digitalmars/D/announce/Transitioning\_to\_a\_type\_aware\_Garbage\_Collector\_6842.html}}.}
\bibitem[NGA9103]{NGA9103}{\hypertarget{nga9103}{} Myron Alexander. ANN: WeakObjectReference - class to hold weakreferences. Grupo de noticias digitalmars.D.announce, 23 de junio de2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/ANN\_WeakObjectReference\_-\_class\_to\_hold\_weak\_references\_9103.html}{Mensaje número 9103} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/announce/ANN\_WeakObjectReference\_-\_class\_to\_hold\_weak\_references\_9103.html}{http://www.digitalmars.com/d/archives/digitalmars/D/announce/ANN\_WeakObjectReference\_-\_class\_to\_hold\_weak\_references\_9103.html}}.}
\bibitem[NGD13301]{NGD13301}{\hypertarget{ngd13301}{} Pete Poulos. Weak references. Grupo de noticias digitalmars.D,5 de agosto de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/weak\_references\_13301.html}{Mensaje número 13301} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/weak\_references\_13301.html}{http://www.digitalmars.com/d/archives/digitalmars/D/learn/weak\_references\_13301.html}}.}
\bibitem[NGD18354]{NGD18354}{\hypertarget{ngd18354}{} Jarrett Billingsley. Does the GC ever perform a generationalcollect? Grupo de noticias digitalmars.D, 5 de marzo de 2005. \href{http://www.digitalmars.com/d/archives/digitalmars/D/18354.html}{Mensajenúmero 18354} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/18354.html}{http://www.digitalmars.com/d/archives/digitalmars/D/18354.html}}.}
\bibitem[NGD22968]{NGD22968}{\hypertarget{ngd22968}{} Maxime Larose. GC pauses. Grupo de noticias digitalmars.D, 2 demayo de 2005. \href{http://www.digitalmars.com/d/archives/digitalmars/D/22968.html}{Mensaje número 22968} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/22968.html}{http://www.digitalmars.com/d/archives/digitalmars/D/22968.html}}.}
\bibitem[NGD2547]{NGD2547}{\hypertarget{ngd2547}{} Mark T. Real time programming why not? Grupo de noticiasdigitalmars.D, 5 de enero de 2002. \href{http://www.digitalmars.com/d/archives/2547.html}{Mensaje número 2547} \footnote{\href{http://www.digitalmars.com/d/archives/2547.html}{http://www.digitalmars.com/d/archives/2547.html}}.}
\bibitem[NGD26273]{NGD26273}{\hypertarget{ngd26273}{} Stewart Gordon. Copying/heap compacting GC. Grupo de noticiasdigitalmars.D, 24 de marzo de 2004. \href{http://www.digitalmars.com/d/archives/26273.html}{Mensaje número 26273} \footnote{\href{http://www.digitalmars.com/d/archives/26273.html}{http://www.digitalmars.com/d/archives/26273.html}}.}
\bibitem[NGD29291]{NGD29291}{\hypertarget{ngd29291}{} Larry Evans. How does RTTI help gc?. Grupo de noticiasdigitalmars.D, 21 de octubre de 2005. \href{http://www.digitalmars.com/d/archives/digitalmars/D/29291.html}{Mensaje número 29291} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/29291.html}{http://www.digitalmars.com/d/archives/digitalmars/D/29291.html}}.}
\bibitem[NGD35364]{NGD35364}{\hypertarget{ngd35364}{} Frank Benoit. GC implementation. Grupo de noticiasdigitalmars.D, 18 de marzo de 2006. \href{http://www.digitalmars.com/d/archives/digitalmars/D/35364.html}{Mensaje número 35364} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/35364.html}{http://www.digitalmars.com/d/archives/digitalmars/D/35364.html}}.}
\bibitem[NGD38689]{NGD38689}{\hypertarget{ngd38689}{} Frank Benoit. GC, the simple solution. Grupo de noticiasdigitalmars.D, 4 de junio de 2006. \href{http://www.digitalmars.com/d/archives/digitalmars/D/38689.html}{Mensaje número 38689} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/38689.html}{http://www.digitalmars.com/d/archives/digitalmars/D/38689.html}}.}
\bibitem[NGD42557]{NGD42557}{\hypertarget{ngd42557}{} Lionello Lunesu. Is a moving GC really needed? Grupo de noticiasdigitalmars.D, 2 de octubre de 2006. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Is\_a\_moving\_GC\_really\_needed\_42557.html}{Mensaje número 425577} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Is\_a\_moving\_GC\_really\_needed\_42557.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Is\_a\_moving\_GC\_really\_needed\_42557.html}}.}
\bibitem[NGD43991]{NGD43991}{\hypertarget{ngd43991}{} Andrey Khropov. {[}Performance{]} shootout.binarytrees whenimplemented with gc is 10x slower than C\# on .NET 2.0. Grupo de noticiasdigitalmars.D, 11 de noviembre de 2006. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Performance\_shootout.binarytrees\_when\_implemented\_with\_gc\_is\_10x\_slower\_than\_C\_on\_.NET\_2.0\_43991.html}{Mensaje número 43991} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Performance\_shootout.binarytrees\_when\_implemented\_with\_gc\_is\_10x\_slower\_than\_C\_on\_.NET\_2.0\_43991.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Performance\_shootout.binarytrees\_when\_implemented\_with\_gc\_is\_10x\_slower\_than\_C\_on\_.NET\_2.0\_43991.html}}.}
\bibitem[NGD44607]{NGD44607}{\hypertarget{ngd44607}{} Russ Lewis. A TODO for somebody: Full Reflection Gets YouSmarter GC. Grupo de noticias digitalmars.D, 20 de noviembre de 2006.\href{http://www.digitalmars.com/d/archives/digitalmars/D/A\_TODO\_for\_somebody\_Full\_Reflection\_Gets\_You\_Smarter\_GC\_44607.html}{Mensaje número 44607} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/A\_TODO\_for\_somebody\_Full\_Reflection\_Gets\_You\_Smarter\_GC\_44607.html}{http://www.digitalmars.com/d/archives/digitalmars/D/A\_TODO\_for\_somebody\_Full\_Reflection\_Gets\_You\_Smarter\_GC\_44607.html}}.}
\bibitem[NGD46407]{NGD46407}{\hypertarget{ngd46407}{} Oskar Linde. The problem with the D GC. Grupo de noticiasdigitalmars.D, 8 de enero de 2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/The\_problem\_with\_the\_D\_GC\_46407.html}{Mensaje número 46407} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/The\_problem\_with\_the\_D\_GC\_46407.html}{http://www.digitalmars.com/d/archives/digitalmars/D/The\_problem\_with\_the\_D\_GC\_46407.html}}.}
\bibitem[NGD54084]{NGD54084}{\hypertarget{ngd54084}{} Babele Dunnit. Problems with GC, trees and array concatenation.Grupo de noticias digitalmars.D, 1ro de junio de 2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Problems\_with\_GC\_trees\_and\_array\_concatenation\_54084.html}{Mensaje número54084} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Problems\_with\_GC\_trees\_and\_array\_concatenation\_54084.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Problems\_with\_GC\_trees\_and\_array\_concatenation\_54084.html}}.}
\bibitem[NGD5622]{NGD5622}{\hypertarget{ngd5622}{} Christian Schüler. D and game programming. Grupo de noticiasdigitalmars.D, 30 de mayo de 2002. \href{http://www.digitalmars.com/d/archives/5622.html}{Mensaje número 5622} \footnote{\href{http://www.digitalmars.com/d/archives/5622.html}{http://www.digitalmars.com/d/archives/5622.html}}.}
\bibitem[NGD5821]{NGD5821}{\hypertarget{ngd5821}{} Antonio Monteiro. Thread and gc.fullCollect. Grupo de noticiasdigitalmars.D, 11 de enero de 2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/thread\_and\_gc.fullCollect\_5821.html}{Mensaje número 5821} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/thread\_and\_gc.fullCollect\_5821.html}{http://www.digitalmars.com/d/archives/digitalmars/D/learn/thread\_and\_gc.fullCollect\_5821.html}}.}
\bibitem[NGD63541]{NGD63541}{\hypertarget{ngd63541}{} Leonardo Maffi. A smaller GC benchmark. Grupo de noticiasdigitalmars.D, 10 de diciembre de 2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/A\_smaller\_GC\_benchmark\_63541.html}{Mensaje número 63541} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/A\_smaller\_GC\_benchmark\_63541.html}{http://www.digitalmars.com/d/archives/digitalmars/D/A\_smaller\_GC\_benchmark\_63541.html}}.}
\bibitem[NGD67673]{NGD67673}{\hypertarget{ngd67673}{} Leonardo Maffi. Slow GC? Grupo de noticias digitalmars.D, 13 demarzo de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Slow\_GC\_67673.html}{Mensaje número 67673} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Slow\_GC\_67673.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Slow\_GC\_67673.html}}.}
\bibitem[NGD69761]{NGD69761}{\hypertarget{ngd69761}{} Jarrett Billingsley. Weak references. Grupo de noticiasdigitalmars.D, 12 de abril de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Weak\_references.\_69761.html}{Mensaje número 69761} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Weak\_references.\_69761.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Weak\_references.\_69761.html}}.}
\bibitem[NGD71869]{NGD71869}{\hypertarget{ngd71869}{} Fawzi Mohamed. large objects and GC. Grupo de noticiasdigitalmars.D, 16 de mayo de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/large\_objects\_and\_GC\_71869.html}{Mensaje número 71869} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/large\_objects\_and\_GC\_71869.html}{http://www.digitalmars.com/d/archives/digitalmars/D/large\_objects\_and\_GC\_71869.html}}.}
\bibitem[NGD74624]{NGD74624}{\hypertarget{ngd74624}{} Pete Poulos. Weak References. Grupo de noticias digitalmars.D,6 de agosto de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Weak\_References\_74624.html}{Mensaje número 74624} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Weak\_References\_74624.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Weak\_References\_74624.html}}.}
\bibitem[NGD75952]{NGD75952}{\hypertarget{ngd75952}{} Alan Knowles. Threading and the Garbage handler mess. Grupo denoticias digitalmars.D, 6 de septiembre de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Threading\_and\_the\_Garbage\_handler\_mess.\_75952.html}{Mensaje número 75952} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Threading\_and\_the\_Garbage\_handler\_mess.\_75952.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Threading\_and\_the\_Garbage\_handler\_mess.\_75952.html}}.}
\bibitem[NGD75995]{NGD75995}{\hypertarget{ngd75995}{} David Simcha. Partially Static GC. Grupo de noticiasdigitalmars.D, 9 de septiembre de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Partially\_Static\_GC\_75995.html}{Mensaje número 75995} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Partially\_Static\_GC\_75995.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Partially\_Static\_GC\_75995.html}}.}
\bibitem[NGD80695]{NGD80695}{\hypertarget{ngd80695}{} David Simcha. Moving GC. Grupo de noticias digitalmars.D, 12 dediciembre de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Moving\_GC\_80695.html}{Mensaje número 80695} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Moving\_GC\_80695.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Moving\_GC\_80695.html}}.}
\bibitem[NGD86840]{NGD86840}{\hypertarget{ngd86840}{} Simon Treny. Keeping a list of instances and garbage-collection.Grupo de noticias digitalmars.D, 29 de marzo de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Keeping\_a\_list\_of\_instances\_and\_garbage-collection\_86840.html}{Mensaje número86840} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Keeping\_a\_list\_of\_instances\_and\_garbage-collection\_86840.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Keeping\_a\_list\_of\_instances\_and\_garbage-collection\_86840.html}}.}
\bibitem[NGD87831]{NGD87831}{\hypertarget{ngd87831}{} Leandro Lucarella. Re: Std Phobos 2 and logging library? Grupode noticias digitalmars.D, 10 de abril de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Std\_Phobos\_2\_and\_logging\_library\_87794.html\#N87831}{Mensaje número 87831} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Std\_Phobos\_2\_and\_logging\_library\_87794.html\#N87831}{http://www.digitalmars.com/d/archives/digitalmars/D/Std\_Phobos\_2\_and\_logging\_library\_87794.html\#N87831}}.}
\bibitem[NGD88065]{NGD88065}{\hypertarget{ngd88065}{} Jason House. D2 weak references. Grupo de noticiasdigitalmars.D, 15 de abril de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/D2\_weak\_references\_88065.html}{Mensaje número 88065} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/D2\_weak\_references\_88065.html}{http://www.digitalmars.com/d/archives/digitalmars/D/D2\_weak\_references\_88065.html}}.}
\bibitem[NGD88298]{NGD88298}{\hypertarget{ngd88298}{} Leandro Lucarella. GC object finalization not guaranteed. Grupode noticias digitalmars.D, 18 de abril de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/GC\_object\_finalization\_not\_guaranteed\_88298.html}{Mensaje número 88298} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/GC\_object\_finalization\_not\_guaranteed\_88298.html}{http://www.digitalmars.com/d/archives/digitalmars/D/GC\_object\_finalization\_not\_guaranteed\_88298.html}}.}
\bibitem[NGD88559]{NGD88559}{\hypertarget{ngd88559}{} Andrei Alexandrescu. -nogc. Grupo de noticias digitalmars.D, 23de abril de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/nogc\_88559.html}{Mensaje número 88559} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/nogc\_88559.html}{http://www.digitalmars.com/d/archives/digitalmars/D/nogc\_88559.html}}.}
\bibitem[NGD89302]{NGD89302}{\hypertarget{ngd89302}{} David Simcha. Destructors and Deterministic Memory Management.Grupo de noticias digitalmars.D, 3 de mayo de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Destructors\_and\_Deterministic\_Memory\_Management\_89302.html}{Mensaje número89302} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Destructors\_and\_Deterministic\_Memory\_Management\_89302.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Destructors\_and\_Deterministic\_Memory\_Management\_89302.html}}.}
\bibitem[NGD89394]{NGD89394}{\hypertarget{ngd89394}{} David Simcha. Associative Arrays and Interior Pointers. Grupo denoticias digitalmars.D, 4 de mayo de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/Associative\_Arrays\_and\_Interior\_Pointers\_89394.html}{Mensaje número 89394} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/Associative\_Arrays\_and\_Interior\_Pointers\_89394.html}{http://www.digitalmars.com/d/archives/digitalmars/D/Associative\_Arrays\_and\_Interior\_Pointers\_89394.html}}.}
\bibitem[NGD90977]{NGD90977}{\hypertarget{ngd90977}{} Anónimo. Why allocation of large amount of small objects so slow(x10) in D? Grupo de noticias digitalmars.D, 21 de mayo de 2009. \href{http://www.digitalmars.com/d/archives/digitalmars/D/why\_allocation\_of\_large\_amount\_of\_small\_objects\_so\_slow\_x10\_in\_D\_90977.html}{Mensajenúmero 90977} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/why\_allocation\_of\_large\_amount\_of\_small\_objects\_so\_slow\_x10\_in\_D\_90977.html}{http://www.digitalmars.com/d/archives/digitalmars/D/why\_allocation\_of\_large\_amount\_of\_small\_objects\_so\_slow\_x10\_in\_D\_90977.html}}.}
\bibitem[NGL13744]{NGL13744}{\hypertarget{ngl13744}{} Alan Knowles. Any advice for GC/memory debugging. Grupo denoticias digitalmars.D.learn, 1ro de septiembre de 2008. \href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/Any\_advice\_for\_GC\_memory\_debugging\_13744.html}{Mensaje número13744} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/Any\_advice\_for\_GC\_memory\_debugging\_13744.html}{http://www.digitalmars.com/d/archives/digitalmars/D/learn/Any\_advice\_for\_GC\_memory\_debugging\_13744.html}}.}
\bibitem[NGL3937]{NGL3937}{\hypertarget{ngl3937}{} Chris K. GC and realtime threads. Grupo de noticiasdigitalmars.D.learn, 12 de julio de 2006. \href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/3937.html}{Mensaje número 3937} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/3937.html}{http://www.digitalmars.com/d/archives/digitalmars/D/learn/3937.html}}.}
\bibitem[NGL8264]{NGL8264}{\hypertarget{ngl8264}{} Robert Fraser. Soft/weak references? Grupo de noticiasdigitalmars.D.learn, 21 de junio de 2007. \href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/Soft\_weak\_references\_8264.html}{Mensaje número 8264} \footnote{\href{http://www.digitalmars.com/d/archives/digitalmars/D/learn/Soft\_weak\_references\_8264.html}{http://www.digitalmars.com/d/archives/digitalmars/D/learn/Soft\_weak\_references\_8264.html}}.}
\bibitem[PAN09]{PAN09}{\hypertarget{pan09}{} Vladimir Panteleev. \href{http://thecybershadow.net/d/Memory\_Management\_in\_the\_D\_Programming\_Language.pdf}{Memory Management in the D ProgrammingLanguage} \footnote{\href{http://thecybershadow.net/d/Memory\_Management\_in\_the\_D\_Programming\_Language.pdf}{http://thecybershadow.net/d/Memory\_Management\_in\_the\_D\_Programming\_Language.pdf}}. Proyecto de licenciatura.  Ministerul Educaţiei şi Tineretuluial Republicii Moldova Universitatea Tehnică a Moldovei Facultatea deCalculatoare, Informatică şi Microelectronică Catedra Filiera Anglofonă.2009.}
\bibitem[PHP530]{PHP530}{\hypertarget{php530}{} PHP Team. \href{http://php.net/releases/5\_3\_0.php}{PHP 5.3.0 Release Announcement} \footnote{\href{http://php.net/releases/5\_3\_0.php}{http://php.net/releases/5\_3\_0.php}}. PHP news archive.2009-06-30.}
\bibitem[RODR97]{RODR97}{\hypertarget{rodr97}{} Gustavo Rodriguez-Rivera and Vince Russo. Non-intrusive CloningGarbage Collection with Stock Operating System Support. Software Practiceand Experience Volumen 27, Número 8. Agosto 1997.}
\bibitem[SHO10]{SHO10}{\hypertarget{sho10}{} Brent Fulgham. \href{http://shootout.alioth.debian.org/}{The Computer Language Benchmarks Game} \footnote{\href{http://shootout.alioth.debian.org/}{http://shootout.alioth.debian.org/}}.2004-2010.}
\bibitem[SUTT99]{SUTT99}{\hypertarget{sutt99}{} Herb Sutter. Exceptional C++: 47 Engineering Puzzles,Programming Problems, and Solutions, 1ra edición. Addison-WesleyProfessional, 1999. ISBN 0-201-61562-2.}
\bibitem[TT1997]{TT1997}{\hypertarget{tt1997}{} Leandro Lucarella. \href{http://www.dsource.org/projects/tango/ticket/1997}{Integrate CDGC (D Concurrent GarbageCollector)} \footnote{\href{http://www.dsource.org/projects/tango/ticket/1997}{http://www.dsource.org/projects/tango/ticket/1997}}. Tango Issue Tracker. Octubre 2010.}
\bibitem[WBB10]{WBB10}{\hypertarget{wbb10}{} Walter Bright. \href{http://www.drdobbs.com/blog/archives/2010/08/c\_compilation\_s.html}{C++ Compilation Speed} \footnote{\href{http://www.drdobbs.com/blog/archives/2010/08/c\_compilation\_s.html}{http://www.drdobbs.com/blog/archives/2010/08/c\_compilation\_s.html}}. Dr. Dobb's Blog. Agosto2010.}
\end{thebibliography}


\renewcommand{\indexname}{Índice de Módulos}

\renewcommand{\indexname}{Índice}
\printindex
\end{document}
