Il s'agit de la version 8.3.0 (développement de la prochaine version) d'un garbage collector conservateur pour C et C++.
Licence : style MIT
Vous trouverez peut-être une version plus récente/stable sur la page de téléchargement ou sur le site BDWGC.
De plus, les dernières corrections de bogues et nouvelles fonctionnalités sont disponibles dans le référentiel de développement.
Il s’agit d’un répartiteur de stockage à usage général pour le garbage collection. Les algorithmes utilisés sont décrits dans :
Boehm, H. et M. Weiser, "Garbage Collection in an Uncooperative Environment", Software Practice & Experience, septembre 1988, pp. 807-820.
Boehm, H., A. Demers et S. Shenker, "Mostly Parallel Garbage Collection", Actes de la conférence ACM SIGPLAN '91 sur la conception et l'implémentation de langages de programmation, SIGPLAN Notices 26, 6 (juin 1991), pp. 157- 164.
Boehm, H., "Space Efficient Conservator Garbage Collection", Actes de la conférence ACM SIGPLAN '91 sur la conception et la mise en œuvre des langages de programmation, Avis SIGPLAN 28, 6 (juin 1993), pp. 197-206.
Boehm H., "Reducing Garbage Collector Cache Misses", Actes du Symposium international 2000 sur la gestion de la mémoire.
Les interactions possibles entre le collecteur et les compilateurs d'optimisation sont discutées dans
Boehm, H. et D. Chase, "A Proposal for GC-safe C Compilation", The Journal of C Language Translation 4, 2 (décembre 1992).
Boehm H., "Simple GC-safe Compilation", Actes de la conférence ACM SIGPLAN '96 sur la conception et la mise en œuvre des langages de programmation.
Contrairement au collecteur décrit dans la deuxième référence, ce collecteur fonctionne soit avec le mutateur arrêté pendant toute la collecte (par défaut), soit de manière incrémentielle pendant les allocations. (Ce dernier est pris en charge sur moins de machines.) Sur les plates-formes les plus courantes, il peut être construit avec ou sans prise en charge des threads. Sur certaines plates-formes, il peut profiter d'un multiprocesseur pour accélérer le garbage collection.
Bon nombre des idées qui sous-tendent le collectionneur ont déjà été explorées par d’autres. Notamment, certains des systèmes d'exécution développés chez Xerox PARC au début des années 1980 analysaient de manière conservatrice les piles de threads pour localiser d'éventuels pointeurs (cf. Paul Rovner, "Sur l'ajout de types de récupération de place et d'exécution à un langage concurrent à vérification statique fortement typé". Xerox PARC CSL 84-7). Doug McIlroy a écrit un collecteur plus simple et entièrement conservateur qui faisait partie de la version 8 d'UNIX (tm), mais qui ne semble pas avoir été largement utilisé.
Des outils rudimentaires permettant d'utiliser le collecteur comme détecteur de fuites sont inclus, tout comme un ensemble de cordes assez sophistiqué "cordon" qui utilise le collecteur. (Voir README.cords et H.-J. Boehm, R. Atkinson et M. Plass, "Ropes: An Alternative to Strings", Software Practice and Experience 25, 12 (décembre 1995), pp. 1315-1330. Ce est très similaire au package "rope" de Xerox Cedar, ou au package "rope" de SGI STL ou de la distribution g++.)
D'autres documents sur les collecteurs sont disponibles dans l'aperçu.
Certaines des utilisations connues du collecteur sont répertoriées sur la page Clients connus de GitHub.
Il s'agit d'un allocateur de stockage de récupération de place destiné à être utilisé comme plug-in de remplacement pour le malloc de C.
Étant donné que le collecteur n'exige pas que les pointeurs soient balisés, il ne tente pas de garantir que tout le stockage inaccessible est récupéré. Cependant, d'après notre expérience, il réussit généralement mieux à récupérer la mémoire inutilisée que la plupart des programmes C utilisant la désallocation explicite. Contrairement aux fuites introduites manuellement, la quantité de mémoire non récupérée reste généralement limitée.
Dans ce qui suit, un « objet » est défini comme étant une région de mémoire allouée par les routines décrites ci-dessous.
Tous les objets non destinés à être collectés doivent être pointés soit à partir d'autres objets accessibles, soit à partir des registres, de la pile, des données ou des segments bss alloués statiquement. Les pointeurs de la pile ou des registres peuvent pointer n'importe où à l'intérieur d'un objet. La même chose est vraie pour les pointeurs de tas si le collecteur est compilé avec ALL_INTERIOR_POINTERS
défini, ou si GC_all_interior_pointers
est autrement défini, comme c'est désormais la valeur par défaut.
La compilation sans ALL_INTERIOR_POINTERS
peut réduire la rétention accidentelle d'objets indésirables, en exigeant des pointeurs depuis le tas vers le début d'un objet. Mais cela ne semble plus être un problème majeur pour la plupart des programmes occupant une petite fraction de l'espace d'adressage possible.
Il existe un certain nombre de routines qui modifient l'algorithme de reconnaissance du pointeur. GC_register_displacement
permet de reconnaître certains pointeurs intérieurs même si ALL_INTERIOR_POINTERS
n'est pas défini. GC_malloc_ignore_off_page
permet d'ignorer certains pointeurs au milieu de gros objets, réduisant considérablement la probabilité de rétention accidentelle de gros objets. Dans la plupart des cas, il semble préférable de compiler avec ALL_INTERIOR_POINTERS
et d'utiliser GC_malloc_ignore_off_page
si vous recevez des avertissements de collecteur suite à des allocations d'objets très volumineux. Voir ici pour plus de détails.
AVERTISSEMENT : les pointeurs dans la mémoire allouée par le malloc
standard (système) ne sont pas vus par le ramasse-miettes. Ainsi, les objets pointés uniquement depuis une telle région peuvent être prématurément désalloués. Il est donc suggéré que le malloc
standard soit utilisé uniquement pour les régions de mémoire, telles que les tampons d'E/S, dont il est garanti qu'elles ne contiennent pas de pointeurs vers une mémoire récupérable. Les pointeurs en langage C, variables automatiques, statiques ou de registre, sont correctement reconnus. (Notez que GC_malloc_uncollectable
a une sémantique similaire à celle de malloc standard, mais alloue des objets suivis par le collecteur.)
ATTENTION : le collecteur ne sait pas toujours trouver les pointeurs dans les zones de données associées aux bibliothèques dynamiques. Il est facile d'y remédier si vous savez comment trouver ces zones de données sur votre système d'exploitation (voir GC_add_roots
). Le code permettant de procéder ainsi sous SunOS, IRIX 5.X et 6.X, HP/UX, Alpha OSF/1, Linux et Win32 est inclus et utilisé par défaut. (Voir README.win32 et README.win64 pour plus de détails sur Windows.) Sur d'autres systèmes, les pointeurs des zones de données de bibliothèque dynamique peuvent ne pas être pris en compte par le collecteur. Si vous écrivez un programme qui dépend du collecteur qui analyse les zones de données de bibliothèque dynamique, il peut être judicieux d'inclure au moins un appel à GC_is_visible
pour garantir que ces zones sont visibles pour le collecteur.
Notez que le garbage collector n'a pas besoin d'être informé des données partagées en lecture seule. Cependant, si le mécanisme de bibliothèque partagée peut introduire des zones de données non contiguës pouvant contenir des pointeurs, le collecteur doit alors en être informé.
Le traitement du signal pour la plupart des signaux peut être différé pendant la collecte et pendant les parties ininterrompues du processus d'allocation. Comme les mallocs ANSI C standard, par défaut, il est dangereux d'invoquer malloc (et d'autres routines GC) à partir d'un gestionnaire de signal alors qu'un autre appel malloc peut être en cours.
L'allocateur/collecteur peut également être configuré pour un fonctionnement thread-safe. (Une sécurité totale du signal peut également être obtenue, mais seulement au prix de deux appels système par malloc, ce qui est généralement inacceptable.)
AVERTISSEMENT : le collecteur ne garantit pas d'analyser le stockage local des threads (par exemple du type accessible avec pthread_getspecific
). Cependant, le collecteur analyse les piles de threads. La meilleure solution consiste donc généralement à garantir que tous les pointeurs stockés dans le stockage local du thread sont également stockés sur la pile du thread pendant toute la durée de leur durée de vie. (Il s'agit sans doute d'un bug de longue date, mais il n'a pas encore été corrigé.)
Il existe plusieurs façons de créer le collecteur :
CMake (c'est la méthode recommandée)
GNU autoconf/automake
Zig (expérimental)
MS nmake (directement)
Makefile.direct
Compilation manuelle en C
Le moyen le plus simple de construire libgc (ainsi que libcord) et d'exécuter les tests en utilisant cmake :
mkdir sorti cmake -Dbuild_tests=ON .. cmake --build .ctest
Il s’agit de la manière la plus multiplateforme de créer une bibliothèque. Voir README.cmake pour plus de détails.
Veuillez noter que le référentiel source du collecteur ne contient pas de fichiers configure
ni de fichiers générés automatiquement similaires. Ainsi, la procédure complète de construction basée sur autoconf du collecteur à partir du référentiel source pourrait ressembler à :
./autogen.sh ./configurer faire un chèque
Le processus de construction de style GNU comprend les cibles et options habituelles. make install
installe libgc et libcord. Essayez ./configure --help
pour voir toutes les options de configuration. Il n'est actuellement pas possible d'exercer toutes les combinaisons d'options de construction de cette façon.
Voir README.autoconf pour plus de détails.
Construire et tester le collecteur à l'aide de zig est simple dans sa forme la plus simple :
test de construction en zigzag
Il est possible de configurer la construction en utilisant des variables, par exemple zig build -Denable_redirect_malloc -Denable_threads=false
. Zig offre une excellente fonctionnalité de compilation croisée, il est configurable comme ceci :
zig build -Dtarget=riscv64-linux-musl
Actuellement, une version nocturne de zig 0.12 est requise, qui peut être téléchargée depuis https://ziglang.org/download/
Sous Windows, en supposant que les outils de build Microsoft soient installés et correctement configurés, il est possible de construire la bibliothèque et d'exécuter les tests en utilisant nmake
directement, par exemple en tapant nmake -f NT_MAKEFILE check
. Cependant, la méthode recommandée consiste à utiliser cmake comme décrit ci-dessus.
Voir README.win32 pour plus de détails.
Pour le processus de construction à l'ancienne (classique) basé sur makefile, en tapant make -f Makefile.direct check
construira automatiquement libgc, libcord, puis exécutera un certain nombre de tests tels que gctest
. Le test est un test quelque peu superficiel de la fonctionnalité du collecteur. L'échec est indiqué par un core dump ou un message indiquant que le collecteur est cassé. gctest
peut prendre une douzaine de secondes pour s'exécuter sur des ordinateurs de bureau 64 bits vintage 2023 raisonnables. Il peut utiliser jusqu'à environ 30 Mo de mémoire.
Makefile.direct générera une bibliothèque libgc.a avec laquelle vous devrez créer un lien.
Enfin, sur la plupart des cibles, le collecteur pourrait être construit et testé directement avec un seul appel du compilateur, comme ceci (l'exemple ne prend pas en charge le multithread) :
cc -I include -o gctest tests/gctest.c extra/gc.c && ./gctest
Par exemple, cela pourrait être pratique à des fins de débogage.
La bibliothèque peut être configurée plus précisément lors de la construction en définissant les macros répertoriées dans le fichier README.macros.
La bibliothèque est construite avec la prise en charge des threads activée (c'est-à-dire pour un fonctionnement thread-safe) par défaut, à moins qu'elle ne soit explicitement désactivée par :
-Denable_threads=false
option passée à cmake
ou zig build
Option --disable-threads
passée à ./configure
Le collecteur fonctionne silencieusement dans la configuration par défaut. En cas de problème, cela peut généralement être modifié en définissant les variables d'environnement GC_PRINT_STATS
ou GC_PRINT_VERBOSE_STATS
. Cela se traduira par quelques lignes de sortie descriptive pour chaque collection. (Les statistiques données présentent quelques particularités. Les choses ne semblent pas s'additionner pour diverses raisons, notamment les pertes de fragmentation. Celles-ci sont probablement beaucoup plus importantes pour le programme artificiel gctest
que pour votre application.)
L'utilisation (clonage) de libatomic_ops
est désormais facultative à condition que le compilateur prenne en charge les intrinsèques atomiques. La plupart des compilateurs modernes le font. L'exception notable est le compilateur MS (à partir de Visual Studio 2022).
Si nécessaire, la plupart des distributions de système d'exploitation ont le package libatomic_ops
; Vous pouvez également le télécharger ou le cloner depuis l'espace https://github.com/ivmai/libatomic_ops.
Le collecteur est actuellement conçu pour fonctionner essentiellement sans modification sur les machines qui utilisent un espace d'adressage plat de 32 bits ou 64 bits. Cela inclut la grande majorité des stations de travail et des PC x86 (i386 ou version ultérieure).
Dans quelques cas (par exemple, OS/2, Win32) un makefile séparé est fourni ; ceux-ci ont un fichier docs/platforms/README.* distinct spécifique à l'hôte.
Les bibliothèques dynamiques ne sont entièrement prises en charge que sous SunOS/Solaris (et même cette prise en charge n'est pas fonctionnelle sur la dernière version de Sun 3), Linux, FreeBSD, NetBSD, IRIX, HP/UX, Win32 (pas win32s) et OSF/1 en DEC. Machines AXP et peut-être quelques autres répertoriées en haut de dyn_load.c. Sur d'autres machines, nous vous recommandons d'effectuer l'une des opérations suivantes :
Ajoutez le support de la bibliothèque dynamique (et envoyez-nous le code).
Utilisez des versions statiques des bibliothèques.
Faites en sorte que les bibliothèques dynamiques utilisent le malloc standard. Cela reste dangereux si la bibliothèque stocke un pointeur vers un objet récupéré. Mais presque toutes les interfaces standards interdisent cela, car elles gèrent correctement les pointeurs pour empiler les objets alloués. ( strtok
est une exception. Ne l'utilisez pas.)
Dans tous les cas, nous supposons que l’alignement du pointeur est cohérent avec celui appliqué par les compilateurs C standard. Si vous utilisez un compilateur non standard, vous devrez peut-être ajuster les paramètres d'alignement définis dans include/private/gc_priv.h
. Notez que cela peut également être un problème avec les enregistrements/structures compressés, si ceux-ci imposent moins d'alignement pour les pointeurs.
Un port vers une machine qui n'est pas adressé par octets ou qui n'utilise pas d'adresses 32 bits ou 64 bits nécessitera un effort majeur. Un portage vers MSDOS ou Win16 est difficile.
Pour les machines non déjà mentionnées, ou pour les compilateurs non standard, quelques suggestions de portage sont fournies ici.
Les routines suivantes sont destinées à être appelées directement par l'utilisateur. Notez qu'en général, seul GC_malloc
est nécessaire. Les appels GC_clear_roots
et GC_add_roots
peuvent être nécessaires si le collecteur doit tracer à partir d'emplacements non standard (par exemple, à partir de zones de données de bibliothèque dynamiques sur une machine sur laquelle le collecteur ne les comprend pas déjà.) Sur certaines machines, il peut être souhaitable de définir GC_stackbottom
sur une bonne approximation de la base de la pile (en bas).
Le code client peut inclure gc.h
, qui définit tous les éléments suivants, ainsi que bien d'autres.
GC_malloc(bytes)
- Alloue un objet d'une taille donnée. Contrairement à malloc, l'objet est effacé avant d'être renvoyé à l'utilisateur. GC_malloc
invoquera le garbage collector lorsqu'il déterminera que cela est approprié. GC_malloc peut renvoyer 0 s'il ne parvient pas à acquérir suffisamment d'espace auprès du système d'exploitation. C’est la conséquence la plus probable d’un manque d’espace. D'autres conséquences possibles sont qu'un appel de fonction échouera en raison d'un manque d'espace dans la pile, ou que le collecteur échouera d'une autre manière parce qu'il ne peut pas maintenir ses structures de données internes, ou qu'un processus système crucial échouera et mettra la machine hors service. La plupart de ces possibilités sont indépendantes de l'implémentation de malloc.
GC_malloc_atomic(bytes)
- Alloue un objet d'une taille donnée dont il est garanti qu'il ne contient aucun pointeur. Il n’est pas garanti que l’objet retourné soit effacé. (Peut toujours être remplacé par GC_malloc
, mais entraîne des temps de collecte plus rapides. Le collecteur fonctionnera probablement plus rapidement si de grands tableaux de caractères, etc. sont alloués avec GC_malloc_atomic
que s'ils sont alloués de manière statique.)
GC_realloc(object, new_bytes)
- Modifie la taille de l'objet pour qu'il ait une taille donnée. Renvoie un pointeur vers le nouvel objet, qui peut ou non être le même que le pointeur vers l'ancien objet. Le nouvel objet est considéré comme atomique si et seulement si l’ancien l’était. Si le nouvel objet est composite et plus grand que l'objet d'origine, les octets nouvellement ajoutés sont effacés. Il est très probable que cela attribue un nouvel objet.
GC_free(object)
- Désallouer explicitement un objet renvoyé par GC_malloc
ou GC_malloc_atomic
, ou des amis. Pas nécessaire, mais peut être utilisé pour minimiser les collections si les performances sont critiques. Probablement une perte de performances pour les très petits objets (<= 8 octets).
GC_expand_hp(bytes)
- Augmente explicitement la taille du tas. (Cela se fait normalement automatiquement si un garbage collection n'a pas réussi à récupérer suffisamment de mémoire. Les appels explicites à GC_expand_hp
peuvent empêcher des collectes inutilement fréquentes au démarrage du programme.)
GC_malloc_ignore_off_page(bytes)
- Identique à GC_malloc
, mais le client promet de conserver un pointeur vers quelque part dans le premier bloc de tas GC (512 .. 4096 octets ou même plus, selon la configuration) de l'objet pendant qu'il est en direct. (Ce pointeur doit normalement être déclaré volatile pour éviter les interférences des optimisations du compilateur.) C'est la méthode recommandée pour allouer tout ce qui est susceptible d'être supérieur à 100 Ko environ. ( GC_malloc
peut entraîner l'échec de la récupération de ces objets.)
GC_set_warn_proc(proc)
- Peut être utilisé pour rediriger les avertissements du collecteur. De tels avertissements devraient être rares et ne doivent pas être ignorés lors du développement du code.
GC_enable_incremental()
- Active la collecte générationnelle et incrémentielle. Utile pour les gros tas sur les machines qui donnent accès aux informations de page sales. Certaines implémentations de bits sales peuvent interférer avec le débogage (en détectant les erreurs d'adresse) et imposer des restrictions sur les arguments du tas aux appels système (puisque les erreurs d'écriture dans un appel système peuvent ne pas être correctement gérées).
GC_register_finalizer(object, proc, data, 0, 0)
et amis - Autoriser l'enregistrement du code de finalisation. Le code de finalisation fourni par l'utilisateur ( (*proc)(object, data)
) est invoqué une fois que l'objet devient inaccessible. Pour des utilisations plus sophistiquées et pour les problèmes d'ordre de finalisation, voir gc.h
.
La variable globale GC_free_space_divisor
peut être ajustée à la hausse par rapport à sa valeur par défaut de 3 pour utiliser moins d'espace et plus de temps de collecte, ou à la baisse pour l'effet inverse. Le définir sur 1 désactivera presque les collections et entraînera une simple augmentation de toutes les allocations dans le tas.
La variable GC_non_gc_bytes
, qui vaut normalement 0, peut être modifiée pour refléter la quantité de mémoire allouée par les routines ci-dessus qui ne doit pas être considérée comme candidate à la collecte. Une utilisation imprudente peut bien entendu entraîner une consommation excessive de mémoire.
Certains réglages supplémentaires sont possibles via les paramètres définis en haut de include/private/gc_priv.h
.
Si seul GC_malloc
est destiné à être utilisé, il peut être approprié de définir :
#define malloc(n) GC_malloc(n) #define calloc(m,n) GC_malloc((m)*(n))
Pour les petits morceaux de code TRÈS gourmand en allocation, gc_inline.h
inclut des macros d'allocation qui peuvent être utilisées à la place de GC_malloc
et ses amis.
Tous les noms visibles de l'extérieur dans le garbage collector commencent par GC_
. Pour éviter les conflits de noms, le code client doit éviter ce préfixe, sauf lors de l'accès aux routines du ramasse-miettes.
Il existe des dispositions pour l'allocation avec des informations de type explicites. Cela est rarement nécessaire. Les détails peuvent être trouvés dans gc_typed.h
.
L'interface Ellis-Hull C++ vers le collecteur est incluse dans la distribution du collecteur. Si vous avez l'intention de l'utiliser, tapez ./configure --enable-cplusplus && make
(ou cmake -Denable_cplusplus=ON . && cmake --build .
, ou make -f Makefile.direct c++
selon le système de build que vous utilisez). Cela crée des fichiers libgccpp.a et libgctba.a, ou leurs équivalents de bibliothèque partagée (libgccpp.so et libgctba.so). Vous devez établir un lien avec le premier (gccpp) ou le second (gctba), mais pas avec les deux. Voir gc_cpp.h
et ici pour la définition de l'interface. Cette interface tente de se rapprocher de la proposition de garbage collection Ellis-Detlefs C++ sans modification du compilateur.
Très souvent il sera également nécessaire d'utiliser gc_allocator.h
et l'allocateur qui y est déclaré pour construire des structures de données STL. Sinon, les sous-objets des structures de données STL seront alloués à l'aide d'un allocateur système, et les objets auxquels ils font référence pourraient être collectés prématurément.
Le collecteur peut être utilisé pour détecter les fuites dans les programmes C destinés à fonctionner avec malloc/free (par exemple, code avec des contraintes extrêmes de temps réel ou de portabilité). Pour ce faire, définissez FIND_LEAK
dans Makefile. Cela amènera le collecteur à imprimer une description d'objet lisible par l'homme chaque fois qu'un objet inaccessible qui n'a pas été explicitement libéré est trouvé. Ces objets seront également automatiquement récupérés.
Si tous les objets sont alloués avec GC_DEBUG_MALLOC
(voir la section suivante), alors, par défaut, la description de l'objet lisible par l'homme contiendra au moins le fichier source et le numéro de ligne auquel l'objet divulgué a été alloué. Cela peut parfois suffire. (Sur quelques machines, il signalera également une trace de pile cryptique. Si ce n'est pas symbolique, il peut parfois être appelé dans une trace de pile symbolique en appelant le programme "foo" avec tools/callprocs.sh foo
. C'est un shell court script qui appelle adb pour étendre les valeurs des compteurs du programme en adresses symboliques. Il a été largement fourni par Scott Schwartz.)
Notez que les fonctionnalités de débogage décrites dans la section suivante peuvent parfois être légèrement MOINS efficaces en mode recherche de fuite, puisque dans ce dernier, GC_debug_free
entraîne en réalité la réutilisation de l'objet. (Sinon, l'objet est simplement marqué comme invalide.) Notez également que la plupart des tests GC ne sont pas conçus pour s'exécuter de manière significative en mode FIND_LEAK
.
Les routines GC_debug_malloc
, GC_debug_malloc_atomic
, GC_debug_realloc
et GC_debug_free
fournissent une interface alternative au collecteur, qui fournit une aide en cas d'erreurs d'écrasement de mémoire, etc. Les objets ainsi alloués sont annotés avec des informations supplémentaires. Certaines de ces informations sont vérifiées lors du garbage collection et les incohérences détectées sont signalées à stderr.
Les cas simples d'écriture après la fin d'un objet alloué doivent être détectés si l'objet est explicitement désalloué ou si le collecteur est invoqué alors que l'objet est actif. La première désallocation d'un objet effacera les informations de débogage associées à un objet, donc des appels répétés accidentellement à GC_debug_free
signaleront la désallocation d'un objet sans informations de débogage. Les erreurs de mémoire insuffisante seront signalées à stderr, en plus de renvoyer NULL
.
La vérification GC_debug_malloc
pendant le garbage collection est activée lors du premier appel à cette fonction. Cela entraînera un certain ralentissement lors des collectes. Si des vérifications fréquentes du tas sont souhaitées, cela peut être réalisé en appelant explicitement GC_gcollect
, par exemple depuis le débogueur.
Les objets alloués GC_debug_malloc
ne doivent pas être transmis à GC_realloc
ou GC_free
, et inversement. Il est cependant acceptable d'allouer uniquement certains objets avec GC_debug_malloc
, et d'utiliser GC_malloc
pour d'autres objets, à condition que les deux pools restent distincts. Dans ce cas, il existe une très faible probabilité que les objets alloués GC_malloc
soient identifiés à tort comme ayant été écrasés. Cela devrait se produire avec une probabilité d’au plus une sur 2**32. Cette probabilité est nulle si GC_debug_malloc
n'est jamais appelé.
GC_debug_malloc
, GC_debug_malloc_atomic
et GC_debug_realloc
prennent deux arguments de fin supplémentaires, une chaîne et un entier. Ceux-ci ne sont pas interprétés par l’allocateur. Ils sont stockés dans l'objet (la chaîne n'est pas copiée). Si une erreur concernant l'objet est détectée, ceux-ci sont imprimés.
Les macros GC_MALLOC
, GC_MALLOC_ATOMIC
, GC_REALLOC
, GC_FREE
, GC_REGISTER_FINALIZER
et amis sont également fournies. Celles-ci nécessitent les mêmes arguments que les routines correspondantes (sans débogage). Si gc.h
est inclus avec GC_DEBUG
défini, ils appellent les versions de débogage de ces fonctions, en passant le nom du fichier actuel et le numéro de ligne comme deux arguments supplémentaires, le cas échéant. Si gc.h
est inclus sans que GC_DEBUG
soit défini, alors toutes ces macros seront définies comme leurs équivalents hors débogage. ( GC_REGISTER_FINALIZER
est nécessaire, car les pointeurs vers des objets contenant des informations de débogage sont en réalité des pointeurs vers un déplacement de 16 octets depuis le début de l'objet, et une certaine traduction est nécessaire lorsque les routines de finalisation sont invoquées. Pour plus de détails sur ce qui est stocké dans l'en-tête, voir la définition du type oh dans le fichier dbg_mlc.c.)
Le collecteur interrompt normalement le code client pendant la durée d'une phase de marquage de garbage collection. Cela peut être inacceptable si une réponse interactive est nécessaire pour des programmes comportant de gros tas. Le collecteur peut également fonctionner en mode « générationnel », dans lequel il tente généralement de collecter uniquement les objets alloués depuis le dernier garbage collection. De plus, dans ce mode, les garbage collection s'exécutent principalement de manière incrémentielle, avec une petite quantité de travail effectuée en réponse à chacune d'un grand nombre de requêtes GC_malloc
.
Ce mode est activé par un appel à GC_enable_incremental
.
La collecte incrémentielle et générationnelle n'est efficace pour réduire les temps de pause que si le collecteur dispose d'un moyen de savoir quels objets ou pages ont été récemment modifiés. Le collecteur utilise deux sources d’informations :
Informations fournies par le système VM. Cela peut être fourni sous une forme parmi plusieurs. Sous Solaris 2.X (et potentiellement sous d'autres systèmes similaires), les informations sur les pages sales peuvent être lues à partir du système de fichiers /proc. Sous d'autres systèmes (par exemple SunOS4.X), il est possible de protéger le tas en écriture et de détecter les erreurs qui en résultent. Sur ces systèmes, nous exigeons que les appels système écrivant sur le tas (autres que la lecture) soient gérés spécialement par le code client. Voir os_dep.c
pour plus de détails.
Informations fournies par le programmeur. L'objet est considéré comme sale après un appel à GC_end_stubborn_change
à condition que la bibliothèque ait été compilée correctement. Cela ne vaut généralement pas la peine de l’utiliser pour des objets de courte durée. Notez que les bogues causés par un appel GC_end_stubborn_change
ou GC_reachable_here
manquant sont susceptibles d'être observés très rarement et difficiles à retracer.
Toute mémoire qui ne comporte pas de pointeur reconnaissable sera récupérée. L'ajout exclusif de liens avant et arrière dans une liste ne suffit pas.
Certains optimiseurs C peuvent perdre le dernier pointeur non dissimulé vers un objet mémoire suite à des optimisations intelligentes. Cela n’a presque jamais été observé dans la pratique.
Ce n'est pas un collecteur en temps réel. Dans la configuration standard, le pourcentage de temps requis pour la collecte doit être constant quelle que soit la taille du segment. Mais les pauses de collecte augmenteront pour les tas plus importants. Ils diminueront avec le nombre de processeurs si le marquage parallèle est activé.
(Sur les machines vintage 2007, les temps GC peuvent être de l'ordre de 5 ms par Mo de mémoire accessible qui doit être analysée et traitée. Votre kilométrage peut varier.) La fonction de collecte incrémentielle/générationnelle peut être utile dans certains cas.
Veuillez traiter les rapports de bogues et les idées de nouvelles fonctionnalités pour les problèmes GitHub. Avant la soumission, veuillez vérifier que cela n'a pas encore été fait par quelqu'un d'autre.
Si vous souhaitez contribuer, soumettez une pull request à GitHub. Veuillez traiter les fichiers modifiés au format clang avant la soumission.
Si vous avez besoin d'aide, utilisez Stack Overflow. Les discussions techniques plus anciennes sont disponibles dans les archives de la liste de diffusion bdwgc
- elles peuvent être téléchargées sous forme de fichier compressé ou consultées sur Narkive.
Pour recevoir les annonces des nouvelles versions, abonnez-vous au flux RSS. (Pour recevoir les notifications par e-mail, un service gratuit tiers comme le flux RSS IFTTT peut être configuré.) Pour être informé de tous les problèmes, veuillez regarder le projet sur GitHub.
Notre intention est de faciliter l'utilisation de bdwgc (libgc), à la fois dans les logiciels libres et propriétaires. Par conséquent, le code du ramasse-miettes conservateur Boehm-Demers-Weiser que nous prévoyons d'être lié dynamiquement ou statiquement dans une application client est couvert par sa propre licence, dont l'esprit est similaire à celui du style MIT.
Les informations exactes sur la licence sont fournies dans le fichier LICENSE.
Tous les contributeurs sont répertoriés dans le fichier AUTEURS.