41 votes

Explication du collecteur de déchets "sans pause" d'Azul.

Je viens de lire ceci :

http://www.artima.com/lejava/articles/azul_pauseless_gc.html

Bien que j'aie une certaine expérience des compilateurs, je n'ai rien fait en rapport avec le garbage collection ; c'est une grosse boîte noire pour moi.

J'ai eu du mal à comprendre les problèmes mentionnés dans l'article. Je comprends le problème (il y a une pause lors de l'exécution de la plupart des garbage collectors), et je comprends qu'ils prétendent que leur implémentation n'a pas ce problème. Mais je ne comprends pas pourquoi/comment le problème se produit en premier lieu (cela semble être supposé compris dans le texte original), et en conséquence je ne comprends pas pourquoi leur solution pourrait fonctionner.

Quelqu'un peut-il m'expliquer :

  1. pourquoi les collecteurs de déchets ont cette pause en général
  2. pourquoi le gc d'Azul n'a pas ce problème ?

J'ai tendance à mieux comprendre ce genre de choses lorsqu'elles sont expliquées graphiquement - un petit schéma de mémoire réalisé avec l'éditeur de code suffirait probablement.

Merci !

50voto

delnan Points 52260

Ils parlent de la pause qui se produit inévitablement lors du compactage du tas. En effet, lorsque vous allouez et désallouez de nombreux objets de tailles différentes au fur et à mesure, vous fragmentez le tas (tout comme vous fragmentez votre disque dur). Lorsque la fragmentation devient trop extrême, vous devez nettoyer/défragmenter/compacter le tas en réservant un énorme morceau de mémoire, en y déplaçant tous les objets (sans aucune fragmentation) et en utilisant leurs anciens emplacements comme un nouveau morceau de mémoire sans aucun objet, c'est-à-dire sans fragmentation.

Lorsque vous faites cela, vous invalidez toutes les références à tous les objets que vous avez déplacés. Pour éviter cela, vous devez empêcher qu'une référence qui se réfère à un emplacement d'objet pré-compacté soit utilisée. Le moyen le plus simple d'y parvenir est de mettre l'application en pause, de déplacer les objets, puis de mettre à jour toutes les références. Bien sûr, cela peut entraîner un surcoût important.

La solution proposée par Azul est donc la suivante : Ils établissent une "barrière de lecture" qui permet à la GC d'intercepter le déréférencement, et de cette façon ils peuvent paresseusement mettre à jour les références qui sont réellement utilisées.

18voto

pourquoi les collecteurs d'ordures ont cette pause en général ?

Les GC fonctionnent en traçant les blocs de tas atteignables à partir d'un ensemble de racines globales (variables globales, piles de threads et registres du CPU). Les GC se situent sur une échelle glissante allant de l'instantané à la volée. Les GC instantanés travaillent à partir d'un instantané des racines globales et de la topologie du tas. Les GC à la volée mettent à jour de manière incrémentielle leur interprétation du tas au fur et à mesure de l'exécution des mutateurs.

Le traçage n'est pas la raison pour laquelle les collecteurs d'ordures font cette pause en général. Il y a des raisons plus importantes pour faire une pause : la relocalisation d'objet étant la principale.

Mais pour en venir aux traceurs à la volée et aux traceurs instantanés et à leur efficacité relative : Le traçage à la volée peut être plus efficace que les traceurs instantanés au début du processus. Le même article auquel vous faites référence pour décrire [VCGC] classe le précédent collecteur Pauseless non générationnel d'Azul comme un traceur de front d'onde précis [3] :

"... La plupart des collecteurs pratiques utilisent des abstractions conservatrices du front d'onde plutôt que la définition précise fournie ici. C'est-à-dire que le front d'onde est suivi à une granularité d'objet. Cependant, le front d'onde précis n'est pas seulement théorique et a récemment été utilisé dans le collecteur assisté par le matériel pour le serveur Java Azul, qui a un bit "non marqué" dans chaque pointeur [2]."

Le C4 d'Azul partage cette qualité, mais l'obtient en utilisant une barrière de lecture LVB purement logicielle et auto-réparatrice.

Les GC à instantanés complets atteignent un débit élevé parce que le collecteur fonctionne presque entièrement indépendamment des mutateurs. indépendamment des mutateurs, mais présentent une latence élevée car la prise d'un instantané entraîne une pause. Les GC entièrement à la volée ont un faible temps de latence car tout est fait de manière incrémentielle, mais un faible débit en raison de la communication fine entre les mutateurs. faible débit en raison de la communication fine entre les mutateurs et le GC.

Un traceur de front d'onde précis est aussi efficace (du point de vue "ne pas passer du temps sur des objets inutiles" discuté dans l'article) qu'un traceur d'arrêt du monde, qui par définition a également un front d'onde précis. Par rapport aux approches basées sur les instantanés, le balayage précis du front d'onde ne ralentit en aucun cas le débit et ne nécessite pas plus de communication entre le collecteur et le mutateur. Il a un débit aussi bon, voire meilleur, car sa précision garantit qu'il n'a jamais à répéter un travail de traçage.

pourquoi le gc d'Azul n'a pas ce problème ?

Ce problème subsiste, mais il a été atténué par la mise en place d'une barrière de lecture matérielle. Des barrières de lecture avaient été proposées auparavant mais les barrières de lecture logicielles dégradent trop le débit parce que les lectures de pointeurs sont beaucoup plus fréquentes que les écritures.

Comme indiqué, si "le problème" était l'inefficacité due au comportement à la volée par rapport au comportement instantané, alors C4 ne l'a pas, car c'est un traceur de front d'onde précis. De plus, le collecteur C4 d'Azul n'a pas besoin ou n'utilise pas de barrière de lecture matérielle, car il fonctionne sur des systèmes x86 et Linux vanille, et obtient un meilleur débit sur ce matériel que les collecteurs de traçage basés sur les instantanés (voir les comparaisons de débit dans [1])...

Cependant, "le problème" dans la question était formulé comme "pourquoi les garbage collectors ont cette pause en général ?". La précision du front d'onde (ou non) n'a pas grand-chose à voir avec les pauses dominantes des collecteurs d'ordures. Il existe des marqueurs concourants et quasi-concourants (même s'ils sont moins efficaces que C4), mais leurs collecteurs font toujours une pause. Le problème est que le traçage n'est qu'une partie de la collecte. Le traçage vous indique seulement ce qui est vivant et où il se trouve. Il ne vous rend pas la mémoire, et il ne défragmente certainement pas la mémoire fragmentée. Ce sujet est discuté en profondeur dans divers articles universitaires (voir les nombreuses références de l'article de C4 [1]).

C'est le compactage (et la relocalisation d'objets qui en découle) qui semble être le talon d'Achille des collecteurs actuellement livrés sur les JVM de serveur, et ce qui leur fait prendre des pauses [importantes]. Le simple fait de déplacer ne serait-ce qu'un seul objet d'un endroit à un autre signifie que vous devez FIXER toutes les références pointant vers cet objet avant que le programme ne les utilise. Pour la plupart des collecteurs commercialisés, cela signifie une pause "stop-the-world" qui empêche l'application de fonctionner pendant que les références sont corrigées.

C4 exploite la barrière LVB auto-réparatrice (un nouveau type de barrière de lecture introduit dans [2] et largement utilisé dans [1] sous forme logicielle uniquement) pour éviter de devoir corriger les références avant que l'application ne soit autorisée à s'exécuter. C'est ainsi qu'il évite la pause que les autres collecteurs finissent par devoir prendre. La qualité d'autoréparation réduit le coût dynamique des barrières de lecture de plusieurs ordres de grandeur par rapport aux barrières précédentes, non autoréparables (comme la barrière de style Brooks utilisée dans d'autres compacteurs concurrents dans des travaux universitaires, et dans certains collecteurs en temps réel). Le résultat de cette réduction spectaculaire du coût des barrières de lecture est qu'il est pratique à utiliser dans la collecte générationnelle et sur les JVM à l'échelle du serveur.

[1] : " C4 : le collecteur à compactage simultané continu ". http://dl.acm.org/citation.cfm?id=1993491&dl=ACM&coll=DL&CFID=85063603&CFTOKEN=84074207 [2] : "L'algorithme GC sans pause" http://static.usenix.org/events/vee05/full_papers/p46-click.pdf [3] : "Correctness-Preserving Derivation of Concurrent Garbage Collection Algorithms" www.srl.inf.ethz.ch/papers/pldi06-cgc.pdf

(Graham Thomas, directeur technique EMEA, Azul Systems)

8voto

Jon Harrop Points 26951

pourquoi les collecteurs d'ordures ont cette pause en général ?

Les GC fonctionnent en traçant les blocs de tas atteignables à partir d'un ensemble de racines globales (variables globales, piles de threads et registres du CPU). Les GC se situent sur une échelle glissante allant de l'instantané à la volée. Les GC instantanés travaillent à partir d'un instantané des racines globales et de la topologie du tas. Les GC à la volée mettent à jour de manière incrémentielle leur interprétation du tas au fur et à mesure de l'exécution des mutateurs.

Les GC à instantané complet atteignent un débit élevé parce que le collecteur fonctionne presque entièrement indépendamment des mutateurs, mais ils ont une latence élevée parce que la prise d'un instantané entraîne une pause. Les GC entièrement à la volée ont une faible latence parce que tout est fait de manière incrémentielle, mais un faible débit à cause de la communication fine entre les mutateurs et le GC.

En pratique, tous les GC se situent quelque part entre ces deux extrêmes. VCGC est avant tout un GC instantané, mais il utilise une barrière d'écriture pour tenir le collecteur au courant des modifications de la topologie du tas. Staccato a été la première GC parallèle, concurrente et en temps réel au monde, mais elle traite encore certaines opérations par lots afin de conserver l'efficacité de l'allocation des piles.

pourquoi le gc d'Azul n'a pas ce problème ?

Ce problème existe toujours, mais il a été atténué par l'implémentation d'une barrière de lecture dans le matériel. Des barrières de lecture avaient été proposées auparavant mais les barrières de lecture logicielles dégradent trop le débit car les lectures de pointeurs sont beaucoup plus fréquentes que les écritures.

1voto

oelewapperke Points 11

Pourquoi un ramasseur de déchets ne pourrait-il pas simplement mprotect(region_it's_working_on, PROT_READ) et mettre en œuvre un SIGSEGV qui met à jour tous les pointeurs de l'objet auquel on accède ? Oui, il faut bien sûr suivre tous les pointeurs vers un objet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X