Gestión de memoria basada en regiones

La administración de memoria basada en regiones  es una forma de administrar la memoria en la que cada objeto creado en la memoria se asigna a una "región" específica.

Una región, también llamada zona, arena [1] , región o contexto de memoria, es un conjunto de objetos asignados que se pueden desasignar de manera eficiente al mismo tiempo. De forma similar a la gestión de memoria basada en pilas , la gestión de memoria basada en regiones facilita la asignación y desasignación de memoria, lo que permite que se realice con una sobrecarga mínima. Pero, en comparación con la pila, la gestión de la memoria mediante regiones puede ser más flexible: permiten que los objetos vivan más tiempo que cuando se colocan en un marco de pila. En implementaciones típicas, todos los objetos en la misma región se asignan en el mismo rango contiguo de direcciones de memoria, de forma similar a cómo se asignan normalmente los marcos de pila.

Beneficios

En comparación con la asignación de memoria basada en pilas, la administración de memoria basada en regiones permite una forma más natural de implementar la asignación de memoria en la programación paralela. Además, las regiones facilitan mucho el trabajo con la virtualización y diversas técnicas de optimización del rendimiento de la memoria, simplificando la tarea de mover simultáneamente todos los objetos pertenecientes a una misma región a la memoria con acceso más rápido o más lento [2] .

Ejemplo

Como ejemplo simple, considere el siguiente código C que asigna y luego libera una estructura de datos como una lista enlazada :

Región * r = crearRegión (); NodoLista * cabeza = NULL ; para ( int yo = 1 ; yo <= 1000 ; yo ++ ) { ListNode * newNode = allocateFromRegion ( r , sizeof ( ListNode )); nuevoNodo -> siguiente = cabeza ; cabeza = nuevoNodo ; } // ... // (use la lista aquí) // ... destroyRegion ( r );

Aunque se necesitaron muchas operaciones para crear la lista vinculada, se puede destruir rápidamente en una operación, liberando el área donde se colocaron los elementos de la lista. No es necesario escanear la lista y eliminar sus elementos individualmente.

Implementación

Las regiones explícitas simples son fáciles de implementar; la siguiente descripción se basa en un artículo de David Hanson [ 3 ] . Cada región se implementa como una lista enlazada de grandes bloques de memoria; cada bloque debe ser lo suficientemente grande para asignar memoria para muchos objetos dentro de él. La estructura de datos de la región contiene un puntero a la siguiente posición libre dentro del bloque y, si el bloque está lleno, el sistema de administración de memoria asigna un nuevo bloque y lo agrega a la lista. Cuando se libera una región, el siguiente puntero de posición libre se restablece al comienzo del primer bloque y la lista completa de bloques ya creados se puede reutilizar para cambiar la posición de los objetos dentro de la región. En una implementación alternativa, cuando se libera una región, la lista de bloques asignados a ella puede devolverse a la lista libre global, desde la cual otras regiones pueden asignar nuevos bloques posteriormente. Sin embargo, dentro de un esquema tan simple, no es posible liberar memoria individualmente de objetos específicos dentro de un bloque.

La sobrecarga por byte asignado es muy baja para este esquema. Casi todos los episodios de asignación de memoria implican solo comparar y actualizar el puntero a la siguiente posición libre. Las únicas excepciones son aquellos episodios en los que se agota la memoria del bloque y el administrador de memoria debe adjuntar un nuevo bloque a la región. Liberar una región es una operación de tiempo fijo que rara vez se realiza. A diferencia de los sistemas típicos de recolección de basura , la administración de datos basada en regiones no necesita marcar cada objeto de datos con su tipo .

Historia y conceptos

El concepto mismo de regiones es muy antiguo. Se implementó por primera vez en 1967 en el paquete de almacenamiento gratuito AED de Douglas Ross , en el que la memoria se dividía en una jerarquía de zonas. Para cada una de las zonas, la disciplina de gestión de memoria podría configurarse individualmente. Cada una de las zonas podría liberarse mediante una operación común. Así, en este paquete de software, Ross implementó por primera vez el concepto de gestión de memoria basada en regiones prácticamente [4] . En 1976 , el tipo de datos AREA se incluyó en el estándar de lenguaje PL/I para la gestión de grupos de estructuras de datos [5] . En 1990, Hanson demostró que las regiones explícitamente definidas en C (a las que llamó arenas) en la gestión de la memoria pueden proporcionar un rendimiento, medido como el tiempo empleado por byte asignado, que supera incluso al mecanismo de asignación de montón más rápido conocido [3] . Las regiones explícitas desempeñaron un papel importante en el desarrollo de una serie de proyectos de software basados ​​en C, incluido Apache HTTP Server , donde se denominan grupos, y PostgreSQL , donde se denominan contextos de memoria [6] . Al igual que la asignación de almacenamiento dinámico tradicional, estos esquemas no brindan seguridad de acceso a la memoria ; un programador puede acceder a una región de la memoria después de que se haya liberado a través de un enlace pendiente u olvidarse de liberar la región, lo que resulta en una fuga de memoria .

Derivación de regiones

En 1988, los científicos comenzaron a explorar cómo usar regiones para la asignación segura de memoria, introduciendo el concepto de inferencia de región . Como parte de esta técnica, el compilador inserta en el código en la etapa de compilación las directivas para asignar y liberar regiones, así como los objetos individuales ubicados en la memoria que están vinculados estáticamente a una región en particular. El compilador sabe cómo hacer esto de tal manera que puede garantizar la ausencia de punteros colgantes y pérdidas de memoria. En sus primeros trabajos, Ruggieri y Murtagh exploraron una variante de esta técnica en la que se crea una región cuando se ejecuta cada función y se libera cuando finaliza [7] . Al hacerlo, utilizaron el análisis de flujo de datos para determinar la vida útil de cada objeto de memoria asignado estáticamente y luego asignar ese objeto para la asignación a la región más joven por el tiempo de creación que contiene objetos con esa vida útil. En 1994, este trabajo se resumió en el trabajo original de Tofte y Talpin, quienes ampliaron la técnica propuesta por Ruggieri y Murtagh para admitir el polimorfismo de tipos y funciones de orden superior en el lenguaje de programación funcional Standard ML . El trabajo de Tofte y Talpin usó un algoritmo diferente basado en la inferencia de tipos y los conceptos teóricos de tipos de regiones y cálculo de regiones [8] [9] . Propusieron una extensión del cálculo lambda, incluyendo regiones como una entidad especial. De hecho, agregaron las siguientes dos construcciones al cálculo lambda:

e 1 en ρ: calcular el resultado de la expresión e 1 y almacenarlo en la región ρ; letregion ρ in e2 end: crea una región y vincúlala a ρ; calcule e 2 , luego libere la región.

Debido a esta estructura sintáctica, las regiones están "anidadas", lo que significa que si r 2 se crea después de r 1 , también debe liberarse antes de r 1 . El resultado es una "pila" de regiones. Además, las regiones deben ser liberadas en la misma función en que fueron creadas. Las restricciones fueron relajadas en parte por Aiken y otros [10] .

Este cálculo lambda extendido estaba destinado a servir como una representación intermedia demostrablemente segura para la memoria para compilar programas de ML estándar en código de máquina. Sin embargo, la creación de un traductor que pudiera dar buenos resultados para programas grandes se topó con una serie de limitaciones prácticas. Tuvieron que resolverse utilizando un nuevo análisis, incluido el trabajo con llamadas recursivas, llamadas recursivas de cola y la eliminación de regiones que contienen solo un valor de la representación intermedia generada. Este trabajo se completó en 1995 [11] . Sus resultados fueron utilizados por ML Kit, una versión de ML cuyo manejo de memoria se basaba en regiones, en lugar de recolección de elementos no utilizados. El advenimiento del ML Kit permitió una comparación directa entre las dos compilaciones de programas de prueba de tamaño mediano, lo que arrojó resultados muy diferentes ("10 veces más rápido y cuatro veces más lento") dependiendo de cuán "apto para la región" sea un programa de prueba en particular. fue [12] . ML Kit finalmente se amplió para aplicaciones grandes. Se implementaron dos adiciones en él: compilación separada de módulos y una técnica híbrida que combina la deducción de los límites de la región con la recolección regular de basura. [13] [14]

Implementación del concepto en otros lenguajes de programación

Luego del desarrollo del ML Kit, se comenzaron a implementar regiones para otros lenguajes de programación:

  • En varias extensiones del lenguaje de programación C :
    • En el dialecto seguro de C , Cyclone , que agregó soporte para regiones explícitas, entre muchas otras características. Este lenguaje se centró principalmente en migrar aplicaciones existentes a C y refinarlas para usar regiones [15] [16] [17] .
    • Una extensión de C llamada RC también implementó regiones explícitas [18] . Pero este lenguaje utiliza el recuento de referencias específicas de la región para garantizar aún más la seguridad de la memoria al garantizar que ninguna región se libere prematuramente [19] [20] . Las regiones reducen la sobrecarga del recuento de referencias, ya que las referencias internas a las regiones no requieren que los contadores se actualicen cuando cambian. RC incluye un sistema de tipo estático explícito para regiones, lo que permite evitar algunas actualizaciones de refcount [21] .
    • Un subconjunto de C llamado Control-C requiere que los programas usen regiones (y solo una región en un momento dado de ejecución). Estas restricciones son consideradas por los autores del lenguaje como parte de su diseño para proporcionar seguridad de memoria estática [22] .
  • Las regiones se han implementado para un subconjunto de Java [23] y se han convertido en un componente crítico de la gestión de memoria en el lenguaje Realtime Java , que las combina con tipos de propiedad para controlar la encapsulación de objetos y eliminar las comprobaciones en tiempo de ejecución para liberar una región [24] [25] [26] . Más recientemente, se ha propuesto un sistema semiautomático para la detección de regiones en aplicaciones Java integradas en tiempo real, que combina análisis estático en tiempo de compilación, políticas de asignación de regiones controladas en tiempo de ejecución y sugerencias de programador a compilador [27] [28] Las regiones son adecuadas para el cómputo en tiempo real , porque el costo de tiempo para mantenerlas es estáticamente predecible y mucho más simple que los recolectores de basura tradicionales.
  • Se han implementado regiones para los lenguajes de programación lógica Prolog [29] [30] y Mercury [31] [32] ; en estas implementaciones, el modelo de inferencia de región de Tofte y Talpin se ha ampliado para declaraciones de retroceso y corte de prólogo .
  • La gestión de memoria basada en regiones se utiliza en el lenguaje de programación paralelo ParaSail . Debido a la ausencia de punteros explícitos en ParaSail [33] , al implementar la gestión de memoria, no hay necesidad de contar con un mecanismo adicional de conteo de referencias.

Desventajas

Los sistemas que usan regiones pueden experimentar problemas en los que las regiones se vuelven muy grandes antes de que se liberen y, por lo tanto, contienen una alta proporción de datos muertos. Estas regiones generalmente se denominan "fugas de memoria" (aunque finalmente se liberan). La reparación de estas fugas puede requerir la reestructuración del programa. Por lo general, se produce agregando nuevas regiones con una vida útil más corta. La depuración de este tipo de problema es particularmente difícil en los sistemas que utilizan la inferencia de región , donde el programador debe comprender el algoritmo de inferencia subyacente al sistema o analizar la representación intermedia en detalle para diagnosticar el problema. La depuración de programas que utilizan recolectores de basura tradicionales es mucho más fácil, y la liberación oportuna de la memoria que tiene fugas se puede lograr sin reestructurar el programa, simplemente eliminando errores lógicos en su construcción. Estas consideraciones han dado lugar a sistemas híbridos que combinan la gestión de memoria basada en regiones y la recolección de basura convencional [13] . Por otro lado, al depurar programas con recolección de basura, también pueden ocurrir filtraciones si se almacenan referencias a datos que no se volverán a utilizar, y esta circunstancia tiene que ser monitoreada mucho más cuidadosamente por el programador que en un sistema con base en regiones. gestión de la memoria.

La administración de memoria basada en regiones funciona mejor cuando el número de regiones es relativamente pequeño y cada región contiene muchos objetos. Los programas que contienen muchas regiones dispersas sufrirán fragmentación interna . Esto, al final, puede conducir a la pérdida de memoria y al tiempo adicional dedicado a administrar regiones. Nuevamente, cuando se trabaja con la salida de la región, este problema puede ser más difícil de diagnosticar.

Técnicas híbridas

Como se mencionó anteriormente, el lenguaje RC utiliza una técnica de gestión de memoria híbrida que incluye regiones y recuento de referencias . Este enfoque reduce la sobrecarga del recuento de referencias, ya que los enlaces entre objetos dentro de una región no requieren actualizar los contadores cuando se modifican, agregan o eliminan. De manera similar, algunos métodos híbridos que utilizan el etiquetado de regiones combinan el seguimiento de accesibilidad de objetos de recolección de elementos no utilizados con regiones. Dichos métodos implican dividir el montón en regiones, realizar un pase de seguimiento que marca las regiones que contienen objetos vivos y luego liberar las regiones sin etiquetar. Este enfoque requiere una desfragmentación constante de la memoria para que sea eficaz [34] .

Notas

  1. en fuentes rusas este término casi no se usa
  2. Esto puede ser necesario, por ejemplo, para colocar todos los objetos relacionados con una instancia específica de un procedimiento ejecutado en paralelo en una sección de memoria cerca de un procesador específico de un sistema multiprocesador .
  3. 1 2 Hanson, David R. Asignación y desasignación rápidas de memoria basadas en la vida útil de los objetos  //  Software: práctica y experiencia: diario. - 1989. - vol. 20 , núm. 1 . - Pág. 5-12 . -doi : 10.1002/ spe.4380200104 . Archivado desde el original el 20 de octubre de 2012.
  4. Ross, Douglas. El paquete de almacenamiento gratuito de AED  (inglés)  // Comunicaciones de la ACM . - 1967. - vol. 10 , núm. 8 _ - Pág. 481-492 . -doi : 10.1145/ 363534.363546 .
  5. Instituto Nacional Estadounidense de Estándares, inc. Lenguaje de programación estándar nacional estadounidense PL/I  (inglés) . — 1976.
  6. 2010 Grupo de desarrollo global de PostgreSQL. Sección 41.3: Gestión de la memoria . Documentación de PostgreSQL 8.2.15 (1996). Consultado el 22 de febrero de 2010. Archivado desde el original el 12 de febrero de 2010.
  7. Ruggieri, Cristina; Murtagh, Thomas P. (1988). “Análisis de por vida de objetos asignados dinámicamente” . POPL '88: Actas del 15º simposio ACM SIGPLAN-SIGACT sobre Principios de los lenguajes de programación . Nueva York, NY, EE. UU.: ACM. DOI : 10.1145/73560.73585 . Consultado el 22 de febrero de 2010 .
  8. Tofte, Mads; Jean-Pierre Talpin (1993). Una teoría de la asignación de pilas en lenguajes tipificados polimórficamente (Informe técnico). Departamento de Ciencias de la Computación, Universidad de Copenhague. 93/15. En Citeseer Archivado el 21 de junio de 2007.
  9. Tofte, Mads ; Talpin, Jean-Pierre (1994). “Implementación del cálculo λ Call-by-Value tipificado utilizando una pila de regiones” . POPL '94: Actas del 21º simposio ACM SIGPLAN-SIGACT sobre Principios de los lenguajes de programación . Nueva York, NY, EE. UU.: ACM. páginas. 188 y ndash, 201. DOI : 10.1145/174675.177855 . ISBN  0-89791-636-0 . Archivado desde el original el 4 de julio de 2014 . Consultado el 15 de abril de 2014 . Parámetro obsoleto utilizado |deadlink=( ayuda )
  10. Aiken, Alex; Manuel Fähndrich, Raph Levien (1995). Mejor gestión de la memoria estática: mejora del análisis basado en regiones de lenguajes de orden superior (informe técnico). Departamento EECS, Universidad de California, Berkeley. UCB/CSD-95-866. En Citeseer Archivado el 21 de junio de 2007.
  11. Birkedal, Lars ; Tofte, Mads ; Weilstrup, Magnus (1996). “De la inferencia de región a las máquinas de von Neumann a través de la inferencia de representación de región” . POPL '96: Actas del 23º simposio ACM SIGPLAN-SIGACT sobre Principios de los lenguajes de programación . Nueva York, NY, EE. UU.: ACM. páginas. 171 y ndash, 183. DOI : 10.1145/237721.237771 . ISBN 0-89791-769-3 . Consultado el 22 de febrero de 2010 .  
  12. Tofte, Mads; Birkedal, Lars; Elsman, Martín; Hallenberg, Niels. Una retrospectiva sobre la gestión de memoria basada en regiones // Computación simbólica de orden superior. - 2004. - T. 17 , N º 3 . S. 245–265 . ISSN 1388-3690 . -doi : 10.1023/B : LISP.0000029446.78563.a4 .
  13. 1 2 Hallenberg, Niels; Elsman, Martín; Tofté, Mads. Combinando inferencia de región y recolección de basura // Avisos SIGPLAN. - 2003. - T. 37 , N º 5 . S. 141–152 . ISSN 0362-1340 . -doi : 10.1145/ 543552.512547 .
  14. Elsman, Martín. Seguridad de recolección de basura para la gestión de memoria basada en regiones  //  Avisos SIGPLAN: diario. - 2003. - vol. 38 , núm. 3 . pág. 123–134 . ISSN 0362-1340 . -doi : 10.1145/ 640136.604190 .
  15. Cyclone: ​​​​Introducción a Regiones . Manual de uso del ciclón . Consultado el 22 de febrero de 2010. Archivado desde el original el 21 de agosto de 2010.
  16. Grossman, Dan; Morrisett, Greg; Jim, Trevor; Hicks, Michael; Wang, Yanling. Gestión de memoria basada en regiones en ciclón // Avisos SIGPLAN. - 2002. - T. 37 , N º 5 . S. 282–293 . -doi : 10.1145/ 543552.512563 .
  17. Hicks, Michael; Morrisett, Greg ; Grossman, Dan (2004). “Experiencia con manejo seguro de memoria manual en ciclón” . ISMM '04: Actas del cuarto simposio internacional sobre gestión de memoria . Nueva York, NY, EE. UU.: ACM. páginas. 73 y ndash, 84. DOI : 10.1145/1029873.1029883 . ISBN 1-58113-945-4 . Consultado el 22 de febrero de 2010 .  
  18. Gay, David RC - Administración de memoria segura basada en regiones para C (enlace descendente) . Página de inicio de David Gay . Intel Labs Berkeley (1999). Consultado el 22 de febrero de 2010. Archivado desde el original el 26 de febrero de 2009. 
  19. Gay, David ; Aiken, Alex (1998). “Gestión de memoria con regiones explícitas” . PLDI '98: Actas de la conferencia ACM SIGPLAN 1998 sobre diseño e implementación de lenguajes de programación . Nueva York, NY, EE. UU.: ACM. páginas. 313 y ndash, 323. DOI : 10.1145/277650.277748 . ISBN 0-89791-987-4 . Consultado el 22 de febrero de 2010 .  
  20. Gay, David Edward (2001). Gestión de memoria con regiones explícitas (PDF) (Tesis de Doctorado en Informática). Universidad de California en Berkeley. Archivado (PDF) desde el original el 7 de septiembre de 2019 . Consultado el 20 de febrero de 2010 . Parámetro obsoleto utilizado |deadlink=( ayuda )
  21. Gay, David ; Aiken, AlexSoporte de idiomas para regiones // Avisos SIGPLAN. - 2001. - T. 36 , N º 5 . — S. 70–80 . — ISSN 0362-1340 . -doi : 10.1145/ 381694.378815.
  22. Kowshik, Sumant; Dhurjati, Dinakar; Advé, Vikram (2002). "Garantizar la seguridad del código sin verificaciones de tiempo de ejecución para sistemas de control en tiempo real" . CASOS '02: Actas de la conferencia internacional de 2002 sobre compiladores, arquitectura y síntesis para sistemas integrados . Nueva York, NY, EE. UU.: ACM. páginas. 288 y ndash, 297. DOI : 10.1145/581630.581678 . ISBN 1-58113-575-0 . Consultado el 22 de febrero de 2010 .  
  23. Christiansen, Morten V. (1998). Gestión de memoria basada en regiones en Java (tesis de Maestría en Ciencias de la Computación). Departamento de Ciencias de la Computación (DIKU), Universidad de Copenhague . Consultado el 20 de febrero de 2010 .  (enlace no disponible)
  24. Beebee, William S.; Rinard, Martín C. (2001). “Una implementación de la memoria con alcance para Java en tiempo real” . EMSOFT '01: Actas del Primer Taller Internacional sobre Software Embebido . Londres, Reino Unido: Springer-Verlag. páginas. 289 y ndash, 305. ISBN  3-540-42673-6 . Consultado el 22 de febrero de 2010 . (enlace no disponible)
  25. Sălcianu, Alexandru; Chandrasekhar Boyapati, William Beebee, Jr., Martin Rinard (2003). Un sistema de tipos para la administración segura de memoria basada en regiones en Java en tiempo real (PDF) (Informe técnico). Laboratorio de Ciencias de la Computación del MIT. MIT-LCS-TR-869. Archivado (PDF) desde el original el 28 de septiembre de 2021 . Consultado el 29-04-2020 . Parámetro obsoleto utilizado |deadlink=( ayuda )
  26. Boyapati, Chandrasekhar ; Salcianu, Alexandru ; Beebee, Jr., William (2003). "Tipos de propiedad para la gestión segura de memoria basada en regiones en Java en tiempo real" . PLDI '03: Actas de la conferencia ACM SIGPLAN 2003 sobre diseño e implementación de lenguajes de programación . Nueva York, NY, EE. UU.: ACM. páginas. 324 y ndash, 337. DOI : 10.1145/781131.781168 . ISBN 1-58113-662-5 . Consultado el 22 de febrero de 2010 .  
  27. Nahkli, Chaker ; Rippert, Christophe ; Salagnac, Guillaume ; Yovine, Sergio (2007). “Administración de memoria eficiente basada en regiones para sistemas integrados en tiempo real con recursos limitados” (PDF) . Actas del "Taller sobre Implementación, Compilación, Optimización de Lenguajes, Programas y Sistemas Orientados a Objetos (ICOOOLPS'2006)" . Archivado (PDF) desde el original el 26 de febrero de 2012 . Consultado el 22 de febrero de 2010 . Parámetro obsoleto utilizado |deadlink=( ayuda )
  28. Salagnac, Guillaume ; Rippert, Christophe (2007). "Gestión de memoria semiautomática basada en regiones para sistemas integrados de Java en tiempo real". RTCSA '07: Actas de la 13.ª Conferencia internacional IEEE sobre aplicaciones y sistemas informáticos integrados y en tiempo real . Washington, DC, EE. UU.: IEEE Computer Society. páginas. 73 y ndash, 80. DOI : 10.1109/RTCSA.2007.67 . ISBN 978-0-7695-2975-2 .  
  29. Makholm, Henning (2000). Gestión de memoria basada en regiones en Prolog (PDF) (Tesis de Maestría en Ciencias de la Computación). Universidad de Copenhague, Dinamarca. Archivado desde el original (PDF) el 5 de junio de 2011 . Consultado el 20 de febrero de 2010 .
  30. Makholm, Henning (2000). “Un administrador de memoria basado en regiones para prolog” . ISMM '00: Actas del segundo simposio internacional sobre gestión de memoria . Nueva York, NY, EE. UU.: ACM. páginas. 25 y 34. DOI : 10.1145/362422.362434 . ISBN 1-58113-263-8 . Consultado el 22 de febrero de 2010 .  
  31. Phan, Quan ; Janssens, GerdaAnálisis de región estática para Mercurio. - Springer Berlín/Heidelberg, 2007. - T. 4670/2007. — S. 317–332. — (Apuntes de clase en informática). - ISBN 978-3-540-74608-9 . -doi :/ 978-3-540-74610-2 .
  32. Fan, Quan ; Somogyi, Zoltan (2008). “Soporte de tiempo de ejecución para la administración de memoria basada en regiones en Mercury” . ISMM '08: Actas del 7º simposio internacional sobre gestión de memoria . Nueva York, NY, EE. UU.: ACM. páginas. 61 y ndash, 70. DOI : 10.1145/1375634.1375644 . ISBN  978-1-60558-134-7 . Archivado desde el original el 01-06-2018 . Consultado el 15 de abril de 2014 . Parámetro obsoleto utilizado |deadlink=( ayuda )
  33. Taft, Tucker Un camino sin punteros hacia la programación paralela orientada a objetos . Blog de ParaSail (2012). Consultado el 14 de septiembre de 2012. Archivado desde el original el 13 de agosto de 2012.
  34. Blackburn, Stephen M .; McKinley, Kathryn S. (2008). "Immix: un recolector de basura de región de marcas con eficiencia de espacio, recolección rápida y rendimiento mutador" . PLDI '08: Actas de la conferencia ACM SIGPLAN 2008 sobre diseño e implementación de lenguajes de programación . Nueva York, NY, EE. UU.: ACM. páginas. 22 y ndash, 32. DOI : 10.1145/1375581.1375586 . ISBN  978-1-59593-860-2 . Archivado desde el original el 19 de noviembre de 2018 . Consultado el 15 de abril de 2014 . Parámetro obsoleto utilizado |deadlink=( ayuda )