Esta es la versión 8.3.0 (desarrollo de la próxima versión) de un recolector de basura conservador para C y C++.
Licencia: estilo MIT
Es posible que encuentre una versión más reciente/estable en la página de descargas o en el sitio BDWGC.
Además, las últimas correcciones de errores y nuevas funciones están disponibles en el repositorio de desarrollo.
Está destinado a ser un asignador de almacenamiento de recolección de basura de uso general. Los algoritmos utilizados se describen en:
Boehm, H. y M. Weiser, "Recolección de basura en un entorno no cooperativo", Software Practice & Experience, septiembre de 1988, págs. 807-820.
Boehm, H., A. Demers y S. Shenker, "Mostly Parallel Garbage Collection", Actas de la Conferencia ACM SIGPLAN '91 sobre diseño e implementación de lenguajes de programación, Avisos SIGPLAN 26, 6 (junio de 1991), págs. 164.
Boehm, H., "Space Efficient Conservative Garbage Collection", Actas de la conferencia ACM SIGPLAN '91 sobre diseño e implementación de lenguajes de programación, Avisos SIGPLAN 28, 6 (junio de 1993), págs.
Boehm H., "Reducción de errores de caché del recolector de basura", Actas del Simposio internacional sobre gestión de la memoria de 2000.
Las posibles interacciones entre el recopilador y los compiladores de optimización se analizan en
Boehm, H. y D. Chase, "Una propuesta para la compilación de C segura para GC", The Journal of C Language Translation 4, 2 (diciembre de 1992).
Boehm H., "Compilación simple segura para GC", Actas de la conferencia ACM SIGPLAN '96 sobre diseño e implementación de lenguajes de programación.
A diferencia del recopilador descrito en la segunda referencia, este recopilador funciona con el mutador detenido durante toda la recopilación (predeterminado) o de forma incremental durante las asignaciones. (Este último es compatible con menos máquinas). En las plataformas más comunes, se puede construir con o sin soporte para subprocesos. En algunas plataformas, puede aprovechar un multiprocesador para acelerar la recolección de basura.
Muchas de las ideas que subyacen al coleccionista han sido exploradas previamente por otros. En particular, algunos de los sistemas de tiempo de ejecución desarrollados en Xerox PARC a principios de la década de 1980 escanearon de forma conservadora pilas de subprocesos para localizar posibles punteros (cf. Paul Rovner, "On Adding Garbage Collection and Runtime Types to a Strongly-Typed Static Checked, Concurrent Language" Xerox PARC CSL 84-7). Doug McIlroy escribió un recopilador más simple y totalmente conservador que formaba parte de la versión 8 UNIX (tm), pero parece no haber recibido un uso generalizado.
Se incluyen herramientas rudimentarias para el uso del colector como detector de fugas, así como un "cordón" bastante sofisticado que hace uso del colector. (Ver README.cords y H.-J. Boehm, R. Atkinson y M. Plass, "Ropes: An Alternative to Strings", Software Practice and Experience 25, 12 (diciembre de 1995), págs. 1315-1330. Este es muy similar al paquete "rope" en Xerox Cedar, o al paquete "rope" en SGI STL o la distribución g++).
Puede encontrar más documentación sobre coleccionistas en la descripción general.
Algunos de los usos conocidos del recopilador se enumeran en la página Clientes conocidos de GitHub.
Este es un asignador de almacenamiento de recolección de basura que está diseñado para usarse como complemento de reemplazo del malloc de C.
Dado que el recopilador no requiere que se etiqueten los punteros, no intenta garantizar que se recupere todo el almacenamiento inaccesible. Sin embargo, según nuestra experiencia, suele tener más éxito a la hora de recuperar memoria no utilizada que la mayoría de los programas en C que utilizan la desasignación explícita. A diferencia de las fugas introducidas manualmente, la cantidad de memoria no recuperada normalmente permanece limitada.
A continuación, se define un "objeto" como una región de memoria asignada por las rutinas que se describen a continuación.
Cualquier objeto que no esté destinado a ser recopilado debe ser apuntado desde otros objetos accesibles o desde los registros, la pila, los datos o los segmentos bss asignados estáticamente. Los punteros de la pila o de los registros pueden apuntar a cualquier lugar dentro de un objeto. Lo mismo ocurre con los punteros del montón si el recopilador se compila con ALL_INTERIOR_POINTERS
definidos o si se establece GC_all_interior_pointers
, como ahora es el valor predeterminado.
La compilación sin ALL_INTERIOR_POINTERS
puede reducir la retención accidental de objetos basura, al requerir punteros desde el montón hasta el comienzo de un objeto. Pero esto ya no parece ser un problema importante para la mayoría de los programas que ocupan una pequeña fracción del posible espacio de direcciones.
Hay una serie de rutinas que modifican el algoritmo de reconocimiento del puntero. GC_register_displacement
permite reconocer ciertos punteros interiores incluso si ALL_INTERIOR_POINTERS
no está definido. GC_malloc_ignore_off_page
permite ignorar algunos punteros en el medio de objetos grandes, lo que reduce en gran medida la probabilidad de retención accidental de objetos grandes. Para la mayoría de los propósitos, parece mejor compilar con ALL_INTERIOR_POINTERS
y usar GC_malloc_ignore_off_page
si recibe advertencias del recopilador sobre asignaciones de objetos muy grandes. Consulte aquí para obtener más detalles.
ADVERTENCIA : el recolector de basura no ve los punteros dentro de la memoria asignada por el malloc
estándar (del sistema). Por lo tanto, los objetos apuntados únicamente desde dicha región pueden desasignarse prematuramente. Por lo tanto, se sugiere que el malloc
estándar se use solo para regiones de memoria, como búferes de E/S, que se garantiza que no contienen punteros a la memoria de recolección de basura. Se reconocen correctamente los punteros en lenguaje C, variables automáticas, estáticas o de registro. (Tenga en cuenta que GC_malloc_uncollectable
tiene una semántica similar a la del malloc estándar, pero asigna objetos rastreados por el recopilador).
ADVERTENCIA : el recopilador no siempre sabe cómo encontrar punteros en áreas de datos asociadas con bibliotecas dinámicas. Esto es fácil de remediar si sabe cómo encontrar esas áreas de datos en su sistema operativo (consulte GC_add_roots
). El código para hacer esto en SunOS, IRIX 5.X y 6.X, HP/UX, Alpha OSF/1, Linux y Win32 se incluye y se utiliza de forma predeterminada. (Consulte README.win32 y README.win64 para obtener detalles sobre Windows). En otros sistemas, es posible que el recopilador no considere los punteros de las áreas de datos de la biblioteca dinámica. Si está escribiendo un programa que depende de que el recopilador escanee áreas de datos de la biblioteca dinámica, puede ser una buena idea incluir al menos una llamada a GC_is_visible
para garantizar que esas áreas sean visibles para el recopilador.
Tenga en cuenta que no es necesario informar al recolector de basura sobre los datos compartidos de solo lectura. Sin embargo, si el mecanismo de la biblioteca compartida puede introducir áreas de datos no contiguas que pueden contener punteros, entonces es necesario informar al recopilador.
El procesamiento de señales para la mayoría de las señales puede diferirse durante la recopilación y durante partes ininterrumpidas del proceso de asignación. Al igual que los mallocs ANSI C estándar, de forma predeterminada no es seguro invocar malloc (y otras rutinas de GC) desde un controlador de señales mientras puede haber otra llamada malloc en progreso.
El asignador/recolector también se puede configurar para un funcionamiento seguro para subprocesos. (También se puede lograr una seguridad total de la señal, pero sólo a costa de dos llamadas al sistema por malloc, lo que suele ser inaceptable).
ADVERTENCIA : el recopilador no garantiza escanear el almacenamiento local de subprocesos (por ejemplo, del tipo al que se accede con pthread_getspecific
). Sin embargo, el recopilador escanea las pilas de subprocesos, por lo que generalmente la mejor solución es garantizar que todos los punteros almacenados en el almacenamiento local del subproceso también se almacenen en la pila del subproceso durante su vida útil. (Podría decirse que se trata de un error de larga data, pero aún no se ha solucionado).
Hay varias formas de crear el recopilador:
CMake (es la forma recomendada)
Autoconf/automake de GNU
Zig (experimental)
MS nmake (directamente)
Makefile.directo
compilación manual c
La forma más sencilla de compilar libgc (así como libcord) y ejecutar las pruebas usando cmake:
mkdir outcd fuera cmake -Dbuild_tests=ON .. cmake --build .ctest
Esta es la forma más multiplataforma de construir la biblioteca. Consulte README.cmake para obtener más detalles.
Tenga en cuenta que el repositorio de origen del recopilador no contiene archivos configure
ni archivos similares generados automáticamente, por lo que el procedimiento completo de compilación basada en autoconf del recopilador desde el repositorio de origen podría verse así:
./autogen.sh ./configurar hacer cheque
El proceso de construcción de estilo GNU comprende los objetivos y opciones habituales. make install
instala libgc y libcord. Pruebe ./configure --help
para ver todas las opciones de configuración. Actualmente no es posible ejercer todas las combinaciones de opciones de construcción de esta manera.
Consulte README.autoconf para obtener más detalles.
Construir y probar el recopilador usando zig es sencillo en su forma más simple:
prueba de construcción en zig
Es posible configurar la compilación mediante el uso de variables, por ejemplo, zig build -Denable_redirect_malloc -Denable_threads=false
. Zig ofrece una excelente funcionalidad de compilación cruzada y se puede configurar de esta manera:
compilación zig -Dtarget=riscv64-linux-musl
Actualmente, se requiere una versión nocturna de zig 0.12, que se puede descargar desde https://ziglang.org/download/
En Windows, suponiendo que las herramientas de compilación de Microsoft estén instaladas y configuradas adecuadamente, es posible compilar la biblioteca y ejecutar las pruebas usando nmake
directamente, por ejemplo, escribiendo nmake -f NT_MAKEFILE check
. Sin embargo, la forma recomendada es utilizar cmake como se describe anteriormente.
Consulte README.win32 para obtener más detalles.
Para el proceso de compilación basado en archivos MAKE de estilo antiguo (clásico), escribir make -f Makefile.direct check
compilará automáticamente libgc, libcord y luego ejecutará una serie de pruebas como gctest
. La prueba es un tanto superficial de la funcionalidad del recopilador. El fallo se indica mediante un volcado de núcleo o un mensaje que indica que el recopilador está averiado. gctest
puede tardar una docena de segundos en ejecutarse en computadoras de escritorio de 64 bits vintage razonables de 2023. Puede utilizar hasta unos 30 MB de memoria.
Makefile.direct generará una biblioteca libgc.a a la que deberá vincular.
Finalmente, en la mayoría de los objetivos, el recopilador podría construirse y probarse directamente con una única invocación del compilador, como este (el ejemplo carece de soporte para subprocesos múltiples):
cc -incluyo -o gctest tests/gctest.c extra/gc.c && ./gctest
Por ejemplo, esto podría ser conveniente para fines de depuración.
La biblioteca se puede configurar con mayor precisión durante la compilación definiendo las macros enumeradas en el archivo README.macros.
La biblioteca está construida con el soporte de subprocesos habilitado (es decir, para operación segura para subprocesos) de forma predeterminada, a menos que lo deshabilite explícitamente mediante:
-Denable_threads=false
opción pasada a cmake
o zig build
--opción --disable-threads
pasada a ./configure
El recopilador funciona silenciosamente en la configuración predeterminada. En caso de problemas, esto generalmente se puede cambiar definiendo las variables de entorno GC_PRINT_STATS
o GC_PRINT_VERBOSE_STATS
. Esto dará como resultado unas pocas líneas de resultado descriptivo para cada colección. (Las estadísticas proporcionadas exhiben algunas peculiaridades. Las cosas no parecen cuadrar por una variedad de razones, en particular las pérdidas por fragmentación. Estas son probablemente mucho más significativas para el programa artificial gctest
que para su aplicación).
El uso (clonación) de libatomic_ops
ahora es opcional siempre que el compilador admita intrínsecos atómicos. La mayoría de los compiladores modernos lo hacen. La excepción notable es el compilador de MS (a partir de Visual Studio 2022).
Si es necesario, la mayoría de las distribuciones de sistemas operativos tienen el paquete libatomic_ops
; Alternativamente, puede descargarlo o clonarlo desde el espacio https://github.com/ivmai/libatomic_ops.
Actualmente, el recopilador está diseñado para ejecutarse esencialmente sin modificaciones en máquinas que utilizan un espacio de direcciones plano de 32 o 64 bits. Eso incluye la gran mayoría de estaciones de trabajo y PC x86 (i386 o posterior).
En algunos casos (por ejemplo, OS/2, Win32) se proporciona un archivo MAKE independiente; estos tienen un archivo docs/platforms/README.* específico del host independiente.
Las bibliotecas dinámicas son completamente compatibles sólo con SunOS/Solaris (e incluso ese soporte no funciona en la última versión de Sun 3), Linux, FreeBSD, NetBSD, IRIX, HP/UX, Win32 (no win32s) y OSF/1 en DEC. Máquinas AXP y quizás algunas otras enumeradas cerca de la parte superior de dyn_load.c. En otras máquinas le recomendamos que haga una de las siguientes cosas:
Agregue soporte de biblioteca dinámica (y envíenos el código).
Utilice versiones estáticas de las bibliotecas.
Haga arreglos para que las bibliotecas dinámicas utilicen el malloc estándar. Esto sigue siendo peligroso si la biblioteca almacena un puntero a un objeto recolectado como basura. Pero casi todas las interfaces estándar lo prohíben, porque manejan correctamente los punteros para apilar los objetos asignados. ( strtok
es una excepción. No lo use).
En todos los casos asumimos que la alineación del puntero es consistente con la impuesta por los compiladores de C estándar. Si utiliza un compilador no estándar, es posible que deba ajustar los parámetros de alineación definidos en include/private/gc_priv.h
. Tenga en cuenta que esto también puede ser un problema con registros/estructuras empaquetados, si imponen una menor alineación para los punteros.
Un puerto a una máquina que no tiene direcciones de bytes o que no utiliza direcciones de 32 o 64 bits requerirá un gran esfuerzo. Un puerto a MSDOS o win16 simple es difícil.
Para máquinas que aún no se han mencionado, o para compiladores no estándar, aquí se proporcionan algunas sugerencias de portabilidad.
Las siguientes rutinas están pensadas para que el usuario las llame directamente. Tenga en cuenta que normalmente sólo es necesario GC_malloc
. Es posible que se requieran llamadas GC_clear_roots
y GC_add_roots
si el recopilador tiene que rastrear desde lugares no estándar (por ejemplo, desde áreas de datos de biblioteca dinámica en una máquina en la que el recopilador aún no los comprende). En algunas máquinas, puede ser conveniente configurar GC_stackbottom
en una buena aproximación de la base de la pila (abajo).
El código del cliente puede incluir gc.h
, que define todo lo siguiente, además de muchos otros.
GC_malloc(bytes)
: asigna un objeto de un tamaño determinado. A diferencia de malloc, el objeto se borra antes de devolverlo al usuario. GC_malloc
invocará al recolector de basura cuando determine que esto es apropiado. GC_malloc puede devolver 0 si no puede adquirir suficiente espacio del sistema operativo. Ésta es la consecuencia más probable de quedarse sin espacio. Otras posibles consecuencias son que una llamada a función fallará debido a la falta de espacio en la pila, o que el recopilador fallará de otras maneras porque no puede mantener sus estructuras de datos internas, o que un proceso crucial del sistema fallará y derribará la máquina. La mayoría de estas posibilidades son independientes de la implementación de malloc.
GC_malloc_atomic(bytes)
: asigna un objeto de un tamaño determinado que se garantiza que no contiene ningún puntero. No se garantiza que el objeto devuelto se borre. (Siempre se puede reemplazar por GC_malloc
, pero da como resultado tiempos de recopilación más rápidos. El recopilador probablemente se ejecutará más rápido si se asignan matrices de caracteres grandes, etc. con GC_malloc_atomic
que si se asignan estáticamente).
GC_realloc(object, new_bytes)
: cambia el tamaño del objeto para que tenga un tamaño determinado. Devuelve un puntero al nuevo objeto, que puede ser o no el mismo que el puntero al objeto antiguo. El nuevo objeto se considera atómico si y sólo si el antiguo lo era. Si el nuevo objeto es compuesto y más grande que el objeto original, los bytes recién agregados se borran. Es muy probable que esto asigne un nuevo objeto.
GC_free(object)
: desasignar explícitamente un objeto devuelto por GC_malloc
o GC_malloc_atomic
, o amigos. No es necesario, pero se puede utilizar para minimizar las colecciones si el rendimiento es crítico. Probablemente una pérdida de rendimiento para objetos muy pequeños (<= 8 bytes).
GC_expand_hp(bytes)
: aumenta explícitamente el tamaño del montón. (Esto normalmente se hace automáticamente si una recolección de basura no pudo recuperar suficiente memoria. Las llamadas explícitas a GC_expand_hp
pueden evitar recolecciones innecesariamente frecuentes al iniciar el programa).
GC_malloc_ignore_off_page(bytes)
: idéntico a GC_malloc
, pero el cliente promete mantener un puntero a algún lugar dentro del primer bloque del montón de GC (512 .. 4096 bytes o incluso más, según la configuración) del objeto mientras está activo. (Este puntero normalmente debe declararse volátil para evitar interferencias de las optimizaciones del compilador). Esta es la forma recomendada de asignar cualquier cosa que probablemente tenga más de 100 KB aproximadamente. ( GC_malloc
puede provocar que no se puedan recuperar dichos objetos).
GC_set_warn_proc(proc)
: se puede utilizar para redirigir las advertencias del recopilador. Estas advertencias deberían ser poco frecuentes y no deberían ignorarse durante el desarrollo del código.
GC_enable_incremental()
: habilita la recopilación generacional e incremental. Útil para grandes cantidades de máquinas que brindan acceso a información sucia de páginas. Algunas implementaciones de bits sucios pueden interferir con la depuración (al detectar errores de dirección) y imponer restricciones a los argumentos del montón para las llamadas al sistema (ya que es posible que los errores de escritura dentro de una llamada al sistema no se manejen bien).
GC_register_finalizer(object, proc, data, 0, 0)
y amigos: permite el registro del código de finalización. El código de finalización proporcionado por el usuario ( (*proc)(object, data)
) se invoca después de que el objeto se vuelve inalcanzable. Para usos más sofisticados y para cuestiones de orden de finalización, consulte gc.h
La variable global GC_free_space_divisor
se puede ajustar hacia arriba desde su valor predeterminado de 3 para usar menos espacio y más tiempo de recolección, o hacia abajo para el efecto opuesto. Establecerlo en 1 casi deshabilitará las colecciones y hará que todas las asignaciones simplemente crezcan en el montón.
La variable GC_non_gc_bytes
, que normalmente es 0, se puede cambiar para reflejar la cantidad de memoria asignada por las rutinas anteriores que no debe considerarse candidata a recopilación. Por supuesto, un uso descuidado puede provocar un consumo excesivo de memoria.
Es posible realizar algunos ajustes adicionales a través de los parámetros definidos cerca de la parte superior de include/private/gc_priv.h
.
Si solo se pretende utilizar GC_malloc
, podría ser apropiado definir:
#define malloc(n) GC_malloc(n) #define calloc(m,n) GC_malloc((m)*(n))
Para piezas pequeñas de código MUY intensivo en asignación, gc_inline.h
incluye algunas macros de asignación que pueden usarse en lugar de GC_malloc
y amigos.
Todos los nombres visibles externamente en el recolector de basura comienzan con GC_
. Para evitar conflictos de nombres, el código del cliente debe evitar este prefijo, excepto cuando se accede a las rutinas del recolector de basura.
Existen disposiciones para la asignación con información de tipo explícita. Esto rara vez es necesario. Los detalles se pueden encontrar en gc_typed.h
.
La interfaz Ellis-Hull C++ para el recopilador se incluye en la distribución del recopilador. Si tiene intención de utilizar esto, escriba ./configure --enable-cplusplus && make
(o cmake -Denable_cplusplus=ON . && cmake --build .
o make -f Makefile.direct c++
dependiendo del sistema de compilación que utilice). Esto crea archivos libgccpp.a y libgctba.a, o sus equivalentes de biblioteca compartida (libgccpp.so y libgctba.so). Debes vincular con el primero (gccpp) o con el segundo (gctba), pero no con ambos. Consulte gc_cpp.h
y aquí para conocer la definición de la interfaz. Esta interfaz intenta aproximarse a la propuesta de recolección de basura de Ellis-Detlefs C++ sin cambios en el compilador.
Muy a menudo también será necesario utilizar gc_allocator.h
y el asignador declarado allí para construir estructuras de datos STL. De lo contrario, los subobjetos de las estructuras de datos STL se asignarán mediante un asignador del sistema y los objetos a los que hacen referencia pueden recopilarse prematuramente.
El recopilador se puede utilizar para rastrear fugas en programas C que están destinados a ejecutarse con malloc/free (por ejemplo, código con restricciones extremas de portabilidad o tiempo real). Para hacerlo, defina FIND_LEAK
en Makefile. Esto hará que el recopilador imprima una descripción de objeto legible por humanos cada vez que encuentre un objeto inaccesible que no haya sido liberado explícitamente. Estos objetos también serán reclamados automáticamente.
Si todos los objetos se asignan con GC_DEBUG_MALLOC
(consulte la siguiente sección), entonces, de forma predeterminada, la descripción del objeto legible por humanos contendrá al menos el archivo fuente y el número de línea en el que se asignó el objeto filtrado. A veces esto puede ser suficiente. (En algunas máquinas, también informará un seguimiento de pila críptico. Si esto no es simbólico, a veces se puede llamar a un seguimiento de pila simbólico invocando el programa "foo" con tools/callprocs.sh foo
. Es un shell corto script que invoca a adb para expandir los valores de los contadores del programa a direcciones simbólicas. Fue proporcionado en gran parte por Scott Schwartz).
Tenga en cuenta que las funciones de depuración descritas en la siguiente sección a veces pueden ser ligeramente MENOS efectivas en el modo de búsqueda de fugas, ya que en este último GC_debug_free
en realidad resulta en la reutilización del objeto. (De lo contrario, el objeto simplemente se marca como no válido). Además, tenga en cuenta que la mayoría de las pruebas de GC no están diseñadas para ejecutarse de manera significativa en el modo FIND_LEAK
.
Las rutinas GC_debug_malloc
, GC_debug_malloc_atomic
, GC_debug_realloc
y GC_debug_free
proporcionan una interfaz alternativa al recopilador, que proporciona ayuda con errores de sobrescritura de memoria y similares. Los objetos asignados de esta manera están anotados con información adicional. Parte de esta información se verifica durante la recolección de basura y las inconsistencias detectadas se informan a stderr.
Los casos simples de escritura más allá del final de un objeto asignado deben detectarse si el objeto se desasigna explícitamente o si se invoca al recopilador mientras el objeto está activo. La primera desasignación de un objeto borrará la información de depuración asociada con un objeto, por lo que las llamadas repetidas accidentalmente a GC_debug_free
informarán la desasignación de un objeto sin información de depuración. Los errores de falta de memoria se informarán a stderr, además de devolver NULL
.
La verificación GC_debug_malloc
durante la recolección de basura se habilita con la primera llamada a esta función. Esto resultará en cierta desaceleración durante las cobranzas. Si se desean comprobaciones frecuentes del montón, esto se puede lograr invocando explícitamente GC_gcollect
, por ejemplo, desde el depurador.
Los objetos asignados GC_debug_malloc
no deben pasarse a GC_realloc
o GC_free
, y viceversa. Sin embargo, es aceptable asignar solo algunos objetos con GC_debug_malloc
y usar GC_malloc
para otros objetos, siempre que los dos grupos se mantengan distintos. En este caso, existe una probabilidad muy baja de que los objetos asignados GC_malloc
se identifiquen erróneamente como si se hubieran sobrescrito. Esto debería suceder con una probabilidad de como máximo uno entre 2**32. Esta probabilidad es cero si nunca se llama GC_debug_malloc
.
GC_debug_malloc
, GC_debug_malloc_atomic
y GC_debug_realloc
toman dos argumentos finales adicionales, una cadena y un número entero. Estos no son interpretados por el asignador. Se almacenan en el objeto (la cadena no se copia). Si se detecta un error que involucra al objeto, se imprimen.
También se proporcionan las macros GC_MALLOC
, GC_MALLOC_ATOMIC
, GC_REALLOC
, GC_FREE
, GC_REGISTER_FINALIZER
y amigas. Estos requieren los mismos argumentos que las rutinas correspondientes (que no son de depuración). Si gc.h
se incluye con GC_DEBUG
definido, llaman a las versiones de depuración de estas funciones, pasando el nombre del archivo actual y el número de línea como dos argumentos adicionales, cuando corresponda. Si gc.h
se incluye sin GC_DEBUG
definido, todas estas macros se definirán en sus equivalentes sin depuración. ( GC_REGISTER_FINALIZER
es necesario, ya que los punteros a objetos con información de depuración son en realidad punteros a un desplazamiento de 16 bytes desde el inicio del objeto, y se necesita cierta traducción cuando se invocan las rutinas de finalización. Para obtener detalles sobre lo que se almacena en el encabezado, consulte la definición del tipo oh en el archivo dbg_mlc.c).
El recolector normalmente interrumpe el código del cliente mientras dura una fase de marca de recolección de basura. Esto puede resultar inaceptable si se necesita una respuesta interactiva para programas con grandes montones. El recolector también puede ejecutarse en modo "generacional", en el que normalmente intenta recopilar sólo los objetos asignados desde la última recolección de basura. Además, en este modo, la recolección de basura se ejecuta principalmente de forma incremental, con una pequeña cantidad de trabajo realizada en respuesta a cada una de una gran cantidad de solicitudes de GC_malloc
.
Este modo se habilita mediante una llamada a GC_enable_incremental
.
La recopilación incremental y generacional es eficaz para reducir los tiempos de pausa sólo si el recopilador tiene alguna forma de saber qué objetos o páginas se han modificado recientemente. El recopilador utiliza dos fuentes de información:
Información proporcionada por el sistema VM. Esto puede proporcionarse en una de varias formas. En Solaris 2.X (y potencialmente en otros sistemas similares), la información de las páginas sucias se puede leer desde el sistema de archivos /proc. En otros sistemas (por ejemplo, SunOS4.X) es posible proteger el montón contra escritura y detectar los fallos resultantes. En estos sistemas requerimos que las llamadas al sistema que se escriben en el montón (que no sean de lectura) sean manejadas especialmente por el código del cliente. Consulte os_dep.c
para obtener más detalles.
Información proporcionada por el programador. El objeto se considera sucio después de una llamada a GC_end_stubborn_change
siempre que la biblioteca se haya compilado adecuadamente. Por lo general, no vale la pena usarlo para objetos de corta duración. Tenga en cuenta que los errores causados por una llamada faltante GC_end_stubborn_change
o GC_reachable_here
probablemente se observen con muy poca frecuencia y sean difíciles de rastrear.
Cualquier memoria que no tenga un puntero reconocible será reclamada. Crear enlaces exclusivos hacia adelante y hacia atrás en una lista no es suficiente.
Algunos optimizadores de C pueden perder el último puntero no disfrazado a un objeto de memoria como consecuencia de optimizaciones inteligentes. Esto casi nunca se ha observado en la práctica.
Este no es un coleccionista en tiempo real. En la configuración estándar, el porcentaje de tiempo necesario para la recopilación debe ser constante en todos los tamaños de montón. Pero las pausas en la recolección aumentarán para los lotes más grandes. Disminuirán con la cantidad de procesadores si el marcado paralelo está habilitado.
(En máquinas antiguas de 2007, los tiempos de GC pueden ser del orden de 5 ms por MB de memoria accesible que debe escanearse y procesarse. Su kilometraje puede variar). La función de recopilación incremental/generacional puede ayudar en algunos casos.
Aborde los informes de errores y las ideas de nuevas funciones para los problemas de GitHub. Antes del envío, compruebe que no lo haya realizado todavía otra persona.
Si desea contribuir, envíe una solicitud de extracción a GitHub. Procese los archivos modificados con formato clang antes de enviarlos.
Si necesita ayuda, utilice Stack Overflow. Las discusiones técnicas más antiguas están disponibles en el archivo de la lista de correo bdwgc
; se puede descargar como un archivo comprimido o explorar en Narkive.
Para recibir anuncios de nuevos lanzamientos, suscríbase al canal RSS. (Para recibir notificaciones por correo electrónico, se puede configurar un servicio gratuito de terceros como IFTTT RSS Feed). Para recibir notificaciones sobre todos los problemas, mire el proyecto en GitHub.
Nuestra intención es facilitar el uso de bdwgc (libgc), tanto en software libre como propietario. Por lo tanto, el código del recolector de basura conservador Boehm-Demers-Weiser que esperamos que se vincule dinámica o estáticamente a una aplicación cliente está cubierto por una licencia propia, que es similar en espíritu a una de estilo MIT.
La información exacta de la licencia se proporciona en el archivo LICENCIA.
Todos los contribuyentes están listados en el archivo AUTORES.