Le GC de comptage de références par rapport au GC de traçage est-il une propriété de langage ou une propriété d'implémentation?

9

On entend parfois «Swift ne fait pas de GC classique (traçage), il utilise ARC».

Mais je ne sais pas s'il y a quelque chose dans la sémantique Swift qui nécessite un comptage de références. Il semble que l'on pourrait construire son propre compilateur Swift et son propre runtime pour utiliser le traçage GC.

Alors, qu'est-ce qui est "compté par référence" à propos de Swift? L'implémentation d'Apple ou la langue elle-même? Y a-t-il des parties de la langue ou de la bibliothèque qui prennent si fortement en charge ARC que nous pouvons utiliser cette étiquette pour la langue elle-même?

Ray Toal
la source

Réponses:

9

Swift garantit qu'une fois la dernière référence à un objet supprimée, l'objet est désinitialisé et le deinitcode est immédiatement exécuté.

L'obtention de ce type de garantie via GC n'est pas possible - du moins, non sans sacrifier les performances. Les mécanismes GC standard garantissent uniquement que le deinitcode sera éventuellement exécuté, par exemple au prochain cycle GC. Pour une sémantique précise, vous avez besoin d'un décompte de références quelque part.

chi
la source
3
Ah, donc la présence de deinitas comme mot-clé et la sémantique qui lui est associée sont en effet les choses qui placent le comptage de références carrément dans le langage, plutôt que dans l'implémentation, le domaine.
Ray Toal
2
Rien n'empêche un runtime GCed de rechercher des objets inaccessibles chaque fois qu'un élément est désalloué. C'est horriblement inefficace.
Raphael
@Raphael Modifié pour être plus précis sur ce point.
chi
3

chi a répondu à la question spécifique du corps sur swift, cette réponse répond à la question plus générale du titre.

Le GC de comptage de références par rapport au GC de traçage est-il une propriété de langage ou une propriété d'implémentation?

GC de comptage de référence et GC de traçage fournissent au programmeur différentes garanties.

Le comptage de références fournit un déterminisme dans l'emplacement dans le flux de programme où un objet est détruit, ce qui peut être important si l'objet possède des ressources rares qui doivent être libérées rapidement. En revanche, il ne peut pas gérer des cycles de références "fortes".

Il appartient à la spécification d'une langue individuelle de savoir si des caractéristiques sont garanties et donc quels choix sont disponibles pour une implémentation conforme.

Peter Green
la source
4
Il est également possible de combiner refcount et GC. Ensuite, le langage peut documenter que les objets ont leur destructeur exécuté dès qu'ils ne sont pas référencés (impliquant un refcount sous une forme ou une autre) et que les cycles de référence seront finalement détruits (impliquant une certaine forme de GC). Alternativement, l'implémentation pourrait le faire alors que le langage ne garantit pas quand les destructeurs sont exécutés (IIRC c'est le cas de Python et son implémentation de référence), auquel cas ce serait une propriété d'implémentation.
Gilles 'SO- arrête d'être méchant'
1

Vous pouvez prendre la langue connue sous le nom de Swift et la renommer "Swift with ARC". Vous pouvez ensuite créer un nouveau langage nommé "Swift with GC" avec exactement la même syntaxe, mais avec moins de garanties sur le moment où les objets sont désalloués.

Dans Swift avec ARC, une fois que le compte de référence est 0, l'objet disparaîtra. Avec la récupération de place, tant que vous avez une référence faible, vous pouvez affecter cette référence faible à une référence forte pour "récupérer" l'objet. (Dans Swift, une fois que le nombre de références est 0, les références faibles sont nulles); c'est une différence majeure.

Et bien sûr, Swift avec ARC garantit que la suppression du dernier décompte de références désallouera immédiatement l'objet. Par exemple, vous pouvez avoir une classe FileWriter, où vous n'êtes pas autorisé à avoir deux instances écrivant dans le même fichier en même temps. Dans Swift avec ARC, vous pourriez dire oldWriter = nil; newWriter = FileWriter (...) et vous sauriez que le nouveau FileWriter n'est créé qu'après la suppression de l'ancien (sauf si vous avez conservé une autre référence); dans Swift avec GC, cela ne fonctionnerait pas.

Une autre différence est que dans "Swift with ARC", les objets qui ne sont référencés que par des cycles de référence forts, mais qui ne sont pas réellement accessibles, sont garantis de ne pas être désalloués.

gnasher729
la source