Maison >développement back-end >Golang >Explication détaillée du mécanisme de collecte des ordures de Golang GC

Explication détaillée du mécanisme de collecte des ordures de Golang GC

藏色散人
藏色散人avant
2020-09-14 09:47:083417parcourir

Ce qui suit est une explication détaillée du mécanisme de collecte des ordures de Golang GC de la colonne tutoriel Golang J'espère que cela sera utile aux amis dans le besoin !

Explication détaillée du mécanisme de collecte des ordures de Golang GC

Résumé

En utilisation réelle de go Au cours du processus d'apprentissage du langage, j'ai rencontré des phénomènes d'utilisation de la mémoire apparemment étranges, j'ai donc décidé de mener des recherches sur le modèle de garbage collection du langage Go. Cet article résume les résultats de l’étude.

Qu'est-ce que la collecte des déchets ?

Autrefois, la gestion de la mémoire était un problème majeur pour les programmeurs développant des applications. Dans les langages de programmation traditionnels au niveau du système (principalement C/C++), les programmeurs doivent gérer soigneusement la mémoire et contrôler l'application et la libération de la mémoire. Si vous n'y faites pas attention, des fuites de mémoire peuvent survenir. Ce type de problème est difficile à trouver et à localiser, et a toujours été un cauchemar pour les développeurs. Comment résoudre ce problème de maux de tête ? Dans le passé, deux méthodes étaient généralement utilisées :

  • Outil de détection des fuites de mémoire. Le principe de cet outil est généralement l'analyse statique du code, qui détecte les segments de code pouvant provoquer des fuites de mémoire au travers du scanner. Cependant, les outils de détection comportent inévitablement des omissions et des lacunes et ne peuvent jouer qu’un rôle d’appoint.
  • Pointeurs intelligents. Il s'agit d'une méthode de gestion automatique de la mémoire introduite en C++. En référençant les objets via des objets pointeurs avec des fonctions de gestion automatique de la mémoire, les programmeurs n'ont pas besoin de prêter trop d'attention à la libération de mémoire et atteignent l'objectif de libération automatique de la mémoire. Cette méthode est la plus utilisée, mais elle a un certain coût d'apprentissage pour les programmeurs (il ne s'agit pas d'un support natif au niveau du langage), et les fuites de mémoire ne peuvent être évitées une fois qu'il y a un scénario où vous oubliez de l'utiliser.

Afin de résoudre ce problème, presque tous les nouveaux langages​​développés ultérieurement (java, python, php, etc.) ont introduit la gestion automatique de la mémoire au niveau du langage – c'est-à-dire le langage les utilisateurs doivent uniquement prêter attention à Vous n'avez pas à vous soucier de la libération de mémoire lors de la demande de mémoire. La libération de mémoire est automatiquement gérée par la machine virtuelle ou le runtime. Ce recyclage automatique des ressources mémoire qui ne sont plus utilisées est appelé garbage collection.

Méthodes courantes de collecte des ordures

Comptage de références

Il s'agit de l'algorithme de collecte des ordures le plus simple, qui est le même que le pointeur intelligent mentionné précédemment. Conservez un nombre de références pour chaque objet. Lorsque l'objet référençant l'objet est détruit ou mis à jour, le nombre de références de l'objet référencé est automatiquement diminué de un. Lorsque l'objet référencé est créé ou attribué à un autre objet, le nombre de références est automatiquement augmenté. par un. Lorsque le compteur de références atteint 0, l'objet est immédiatement recyclé.

L'avantage de cette méthode est qu'elle est simple à mettre en œuvre et que la mémoire est recyclée dans les meilleurs délais. Cet algorithme est largement utilisé dans les systèmes avec une mémoire restreinte et des performances en temps réel élevées, tels que le framework iOS Cocoa, PHP, Python, etc. L'algorithme simple de comptage de références présente également des inconvénients évidents :

  • La mise à jour fréquente du décompte de références réduit les performances. Une solution simple consiste pour le compilateur à fusionner les opérations de mise à jour du nombre de références adjacentes en une seule mise à jour ; une autre méthode consiste à ne pas compter les références de variables temporaires fréquentes, mais à analyser la pile pour confirmer si la référence atteint 0. Il existe également des références d'objet temporaires qui déterminent s'il faut les libérer. Il existe de nombreuses autres méthodes, veuillez vous référer ici pour plus de détails.
  • Problème de référence circulaire. Lorsqu'une référence circulaire se produit entre des objets, les objets de la chaîne de référence ne peuvent pas être libérés. La solution la plus évidente consiste à éviter les références circulaires. Par exemple, Cocoa introduit deux types de pointeurs : le pointeur fort et le pointeur faible. Ou bien le système détecte les références circulaires et brise de manière proactive la chaîne circulaire. Bien entendu, cela augmente également la complexité du garbage collection.

Marquer et balayer

Cette méthode est divisée en deux étapes. Mark commence à partir de la variable racine et parcourt tous les objets référencés. Les objets sont accessibles via le parcours de l'application. Tous les objets sont. marquée comme « référencée » une fois le marquage terminé, l'opération d'effacement est effectuée et la mémoire non marquée est recyclée (le recyclage peut être accompagné d'opérations de défragmentation). Cette méthode résout les défauts du comptage de références, mais elle présente également un problème évident : chaque fois que le garbage collection est démarré, toute l'exécution normale actuelle du code sera suspendue et le recyclage réduira considérablement la réactivité du système ! Bien entendu, de nombreuses variantes de l’algorithme mark&sweep (telles que la méthode de marquage tricolore) ont vu le jour pour optimiser ce problème.

Collection générationnelle (génération)

Après de nombreuses observations réelles, nous savons que dans les langages de programmation orientés objet, le cycle de vie de la plupart des objets est très court. L'idée de base de la collection générationnelle est de diviser le tas en deux ou plusieurs espaces appelés générations. Les objets nouvellement créés sont stockés dans ce qu'on appelle la jeune génération (d'une manière générale, la taille de la jeune génération sera beaucoup plus petite que celle de l'ancienne génération). Avec l'exécution répétée du garbage collection, les objets avec des cycles de vie plus longs seront promus (promotion). ) à l'ancienne génération. Par conséquent, deux méthodes différentes de garbage collection, le garbage collection de nouvelle génération et le garbage collection d’ancienne génération, ont vu le jour, qui sont utilisées pour effectuer le garbage collection sur les objets dans leurs espaces respectifs. La vitesse du garbage collection dans la nouvelle génération est très rapide, plusieurs ordres de grandeur plus rapide que celle de l'ancienne génération. Même si la fréquence du garbage collection dans la nouvelle génération est plus élevée, l'efficacité d'exécution est toujours meilleure que celle de l'ancienne génération. génération. En effet, le cycle de vie de la plupart des objets est très court et il n'est pas du tout nécessaire de les promouvoir auprès de l'ancienne génération.

Le garbage collector de GO

Le garbage collection du langage go utilise généralement l'algorithme classique de marquage et de balayage.

  • Avant la version 1.3, l'algorithme de garbage collection de golang était très rudimentaire, et ses performances étaient également largement critiquées : dans certaines conditions (la mémoire dépasse le seuil ou périodiquement, comme 2 minutes), le runtime go suspendra toutes les tâches, exécutera une opération de marquage et de balayage et démarrera l'exécution de toutes les tâches une fois l'opération terminée. Dans les scénarios où beaucoup de mémoire est utilisée, le programme Go connaîtra un phénomène de blocage très évident (Stop The World) lors de l'exécution du garbage collection. Dans les processus de service en arrière-plan qui nécessitent une vitesse de réponse élevée, ce type de retard est tout simplement intolérable ! Au cours de cette période, de nombreuses équipes nationales et étrangères qui pratiquaient le langage Go dans des environnements de production avaient plus ou moins marché sur les pièges de gc. À cette époque, une méthode courante pour résoudre ce problème consistait à contrôler la quantité de mémoire allouée automatiquement le plus rapidement possible afin de réduire la charge gc et à utiliser la gestion manuelle de la mémoire pour gérer les scénarios nécessitant de grandes quantités de mémoire et une allocation haute fréquence.
  • À partir de la version 1.3, l'équipe go a commencé à améliorer et à optimiser continuellement les performances de gc. Lorsque chaque nouvelle version de go est publiée, les améliorations de gc sont devenues le centre de l'attention de tous. Dans la version 1.3, le runtime go sépare les opérations de marquage et de balayage. Comme auparavant, il suspend d'abord l'exécution de toutes les tâches et démarre le marquage, puis redémarre immédiatement les tâches suspendues. la tâche coroutine ordinaire exécutée en parallèle avec d’autres tâches. S'il est exécuté sur un processeur multicœur, go essaiera d'exécuter la tâche gc sur un cœur distinct sans affecter l'exécution du code métier. La propre déclaration de l'équipe Go est que le temps de pause a été réduit de 50 à 70 %.
  • La version 1.4 (la dernière version stable) n'apporte pas beaucoup de changements de performances à gc. Dans la version 1.4, une grande partie du code d'exécution a remplacé l'implémentation native du langage C par l'implémentation du langage Go. Un changement majeur apporté à gc est qu'il peut obtenir un gc précis. L'implémentation du langage C ne peut pas obtenir les informations sur les objets de la mémoire pendant gc, elle ne peut donc pas distinguer avec précision les variables ordinaires des pointeurs. Elle ne peut traiter les variables ordinaires que comme des pointeurs si, par hasard, il y a d'autres objets dans l'espace pointé par cette variable ordinaire. , alors cet objet ne sera pas recyclé. L'implémentation du langage Go connaît parfaitement les informations de type de l'objet et ne traversera que l'objet pointé par le pointeur lors du marquage, évitant ainsi le gaspillage de mémoire tas dans l'implémentation C (résolution d'environ 10 à 30 %).
  • Dans la version 1.5, l'équipe go a apporté des améliorations majeures à gc (des préfigurations ont été posées dans la version 1.4, comme l'introduction de la barrière en écriture. L'objectif principal officiel est de réduire les retards). Le ramasse-miettes implémenté dans Go 1.5 est un « ramasse-miettes non générationnel, sans déplacement, simultané, à marquage et balayage tricolore ». L'algorithme générationnel a été mentionné ci-dessus et constitue une stratégie de gestion du garbage collection relativement bonne. Cependant, il n'a pas été implémenté dans la version 1.5. Je suppose que les étapes ne peuvent pas être trop importantes et doivent être progressivement améliorées. sera implémenté dans Considéré dans l'optimisation gc de la version 1.6. Dans le même temps, la méthode de marquage tricolore présentée ci-dessus est introduite. L'opération de marquage de cette méthode peut être exécutée progressivement sans analyser la totalité de l'espace mémoire à chaque fois, ce qui peut réduire le temps d'arrêt du monde. Cela montre que les performances de garbage collection de Go se sont améliorées jusqu'à la version 1.5. Cependant, pour les systèmes de garbage collection relativement matures (tels que java jvm et javascript v8), go a encore un long chemin à optimiser (mais Je crois que l'avenir doit être merveilleux ~).

Expérience pratique

Le problème le plus courant et le plus difficile rencontré par l'équipe lors de la pratique du langage go était le problème de mémoire (principalement gc). Voici les problèmes et expériences rencontrés en résumé. , tout le monde est invité à communiquer et à discuter.

Le problème d'utilisation importante de la mémoire du programme go

Ce problème a été découvert lorsque nous avons effectué un test de stress sur le service en arrière-plan. Nous avons simulé un grand nombre de demandes d'utilisateurs pour accéder au service en arrière-plan. À ce stade, chaque module de service peut observer une augmentation significative de l'utilisation de la mémoire. Cependant, lorsque le test de résistance a été arrêté, l’utilisation de la mémoire n’a pas diminué de manière significative. Il a fallu beaucoup de temps pour localiser le problème, en utilisant diverses méthodes telles que gprof, mais aucune cause n'a toujours été trouvée. Finalement, j'ai découvert que c'était normal à ce moment-là... Il y a deux raisons principales,

Tout d'abord, le garbage collection de Go a un seuil de déclenchement, qui augmentera progressivement à mesure que chaque utilisation de la mémoire augmente (par exemple, si le seuil initial est de 10 Mo, la prochaine fois, il sera de 20 Mo, et la prochaine fois, il deviendra de 40 Mo. ..), si gc go n'est pas déclenché pendant une longue période, il se déclenchera activement une fois (2min). Une fois que l'utilisation de la mémoire augmente pendant les heures de pointe, à moins que vous ne continuiez à demander de la mémoire, il est presque impossible de déclencher gc en fonction du seuil. Au lieu de cela, vous devez attendre jusqu'à 2 minutes pour que le gc actif démarre avant de déclencher gc.

La deuxième raison est que lorsque le langage Go renvoie la mémoire au système, il indique simplement au système que la mémoire n'est plus nécessaire et peut être recyclée en même temps, le système d'exploitation adoptera un système d'exploitation. stratégie de « retard », qui ne recycle pas immédiatement, mais attendra que la mémoire système soit saturée avant de commencer le recyclage, de sorte que lorsque le programme redemande de la mémoire, il puisse obtenir une vitesse d'allocation extrêmement rapide.

Le problème du long temps de gc

Pour les programmes back-end qui obligent les utilisateurs à répondre aux événements, arrêter le monde à temps partiel pendant Golang gc est un cauchemar. Selon l'introduction ci-dessus, les performances gc de la version 1.5 de go seront considérablement améliorées après avoir terminé les améliorations ci-dessus. Cependant, tous les langages de garbage collection seront inévitablement confrontés à une dégradation des performances pendant gc. À cet égard, nous devrions essayer d'éviter. créer fréquemment des tas temporaires (tels que &abc{}, new, make, etc.) pour réduire le temps d'analyse lors de la récupération de place. Pour les objets temporaires qui doivent être utilisés fréquemment, envisagez de les réutiliser directement via le cache du tableau. utilisez la méthode cgo pour gérer la mémoire eux-mêmes et contourner le garbage collection. , cette méthode n'est pas recommandée à moins qu'elle ne soit absolument nécessaire (elle peut facilement causer des problèmes imprévisibles). Bien sûr, elle peut toujours être envisagée si elle est absolument nécessaire. de cette méthode est encore très évidente~

Fuite par goroutine Problème

L'un de nos services doit gérer de nombreuses demandes de connexion longues Lors de la mise en œuvre, une coroutine de lecture et d'écriture est ouverte pour chaque longue connexion. demande, et une boucle for sans fin est utilisée pour traiter en continu les données d'envoi et de réception. Lorsque la connexion est fermée par l'extrémité distante, si ces deux coroutines ne sont pas traitées, elles continueront à fonctionner et les canaux occupés ne seront pas libérés... Vous devez être très prudent ici, et vous devez les supprimer après ne pas les utiliser. les coroutines. Fermez le canal dépendant et déterminez si le canal est fermé dans la coroutine pour assurer sa sortie.

Connaissances de base de Golang-gc

30 AVRIL 2016 20:02 | COMMENTAIRES

Cette partie présente principalement quelques connaissances introductives de Golang gc, car le contenu de gc implique Il y en a d'autres, et je vais les trier petit à petit.

Contexte de Golang GC

  • Golang est un langage basé sur le garbage collection, qui est son principe de conception.
  • En tant que langage doté d'un garbage collector, l'efficacité de l'interaction de gc avec le programme affectera l'efficacité opérationnelle de l'ensemble du programme.
  • Habituellement, la gestion de la mémoire du programme lui-même affectera l'efficacité entre gc et le programme, et provoquera même des goulots d'étranglement dans les performances.

Problèmes liés à Golang GC

La référence principale est la suivante :

http://morsmachine.dk/machine-gc

est 14 Il a été écrit en 2008. On estime que le mécanisme gc à cette époque était relativement simple. La nouvelle version de golang devrait avoir des changements plus importants par rapport à gc

Il y a aussi la partie pertinente sur golang gc dans le langage go. notes de lecture

À propos des fuites de mémoire

Le terme « Memory Leak » me semble familier, mais en fait je n'ai jamais vu sa signification précise. La

Fuite de mémoire s'explique du point de vue du système d'exploitation. La métaphore frappante est que « l'espace de stockage (espace de mémoire virtuelle) que le système d'exploitation peut fournir à tous les processus est utilisé. par un certain processus "Drain", la raison en est que lorsque le programme est en cours d'exécution, il ouvrira dynamiquement et en continu de l'espace de stockage, et ces espaces de stockage ne seront pas libérés à temps une fois l'opération terminée. Après qu'une application ait alloué un certain segment de mémoire, en raison d'erreurs de conception, le programme peut perdre le contrôle du segment de mémoire, entraînant un gaspillage d'espace mémoire.

Si un programme demande un morceau de mémoire dans l'espace mémoire, puis après la fin du programme, l'espace mémoire n'est pas libéré et le programme correspondant ne dispose pas d'un bon mécanisme gc pour exécuter l'espace Le recyclage demandé par le programme entraînera des fuites de mémoire.

Du point de vue de l'utilisateur, la fuite de mémoire en elle-même ne causera aucun dommage, car elle n'affecte pas les fonctions de l'utilisateur, mais si une "fuite de mémoire" se produit

Pour C et C++, pour les langages ​​sans Garbage Collection, nous nous concentrons principalement sur deux types de fuites de mémoire :

  • Fuite de tas. La mémoire fait référence à un morceau de mémoire alloué à partir du tas via malloc, realloc new, etc. selon les besoins lorsque le programme est en cours d'exécution, il doit être supprimé en appelant le free ou delete correspondant. Si l'erreur de conception du programme empêche la libération de cette partie de la mémoire, alors cette mémoire ne sera pas utilisée à l'avenir et une fuite de tas se produira
  • Fuite de ressources système (Resource Leak). Se réfère principalement à l'utilisation du système par le programme. Les ressources allouées telles que Bitmap, handle, SOCKET, etc. ne sont pas libérées en utilisant les fonctions correspondantes, ce qui entraîne un gaspillage de ressources système, ce qui peut sérieusement entraîner une réduction des performances du système et un système instable. opération.

Il existe de nombreux problèmes liés aux fuites de mémoire, qui ne seront pas abordés ici.

Modes GC courants

Pour les avantages et les inconvénients spécifiques, veuillez vous référer à ceci. Voici juste une introduction générale.

  • Comptage de références (comptage de références) Chaque objet maintient un compteur de références. Lorsque l'objet qui fait référence à l'objet est détruit ou mis à jour, le compteur de références de l'objet référencé est automatiquement décrémenté de 1. Lorsque le compteur de références est automatiquement décrémenté de 1. appliqué Lorsqu'un objet est créé ou attribué à un autre objet, la référence est +1, et lorsque la référence est 0, il est recyclé. L'idée est simple, mais la mise à jour fréquente du compteur de référence réduit les performances, et il y a une boucle de référence. (utilisé par php, Python)
  • Marquer et balayer sont ce que golang utilise. Il parcourt tous les objets référencés à partir de la variable racine, effectue des opérations claires après le marquage et recycle les objets non marqués. Inconvénient : tout le garbage collection sera suspendu. à chaque fois Pour un code exécuté normalement, la réactivité du système sera considérablement réduite. Diverses variantes de marquage et de marais (méthode de marquage en trois couleurs) peuvent atténuer les problèmes de performances.
  • Collection générationnelle (génération) jvm utilise l'idée du recyclage générationnel. Dans les langages de programmation orientés objet, le cycle de vie de la plupart des objets est très court. L'idée de base de la collection générationnelle est de diviser le tas en deux ou plusieurs espaces appelés générations. Les objets nouvellement créés sont stockés dans ce qu'on appelle la jeune génération (d'une manière générale, la taille de la jeune génération sera beaucoup plus petite que celle de l'ancienne génération, avec l'exécution répétée du garbage collection, le cycle de vie est). Les objets seront promus auprès de l’ancienne génération (on utilise ici une idée de classification, qui est aussi une idée fondamentale de la pensée scientifique).

Par conséquent, deux méthodes différentes de collecte des ordures, la collecte des ordures de nouvelle génération et la collecte des ordures de l'ancienne génération, ont vu le jour (classer d'abord, puis prescrire le bon médicament), qui sont utilisées pour effectuer la collecte des ordures sur objets dans leurs espaces respectifs. La vitesse du garbage collection dans la nouvelle génération est très rapide, plusieurs ordres de grandeur plus rapide que celle de l'ancienne génération. Même si la fréquence du garbage collection dans la nouvelle génération est plus élevée, l'efficacité d'exécution est toujours meilleure que celle de l'ancienne génération. génération. En effet, le cycle de vie de la plupart des objets est très court et il n'est pas du tout nécessaire de les promouvoir auprès de l'ancienne génération.

Comment fonctionne habituellement gc dans Golang

Le gc dans Golang est essentiellement l'idée de l'effacement des marques :

Dans le tas de mémoire (en raison de la gestion parfois de la mémoire Le tas La structure de données est utilisée lors de la création de pages, elle est donc appelée mémoire tas) qui stocke une série d'objets, qui peuvent être liés à d'autres objets (références entre ces objets, un garbage collector de traçage arrêtera le programme à un moment donné). qui est en cours d'exécution, puis il analysera l'ensemble d'objets déjà connu que le runtime connaît déjà. Il s'agit généralement de variables globales et de divers objets qui existent dans la pile. gc marquera ces objets, marquera le statut de ces objets comme accessibles, trouvera toutes les références d'objets dans d'autres endroits qui peuvent être atteints à partir des objets actuels et marquera ces objets comme objets accessibles. Cette étape est appelée phase de marquage, c'est-à-dire. c'est-à-dire phase de marquage. L'objectif principal de cette étape est d'obtenir les informations d'état de ces objets.

Une fois tous ces objets analysés, gc obtiendra tous les objets inaccessibles (objets avec un statut inaccessible) et les recyclera. Cette étape est appelée phase de balayage, qui estPhase de nettoyage.

gc collecte uniquement les objets qui ne sont pas marqués comme accessibles. Si gc ne reconnaît pas de référence, un objet encore utilisé peut éventuellement être recyclé, provoquant une erreur d'exécution du programme.

Vous pouvez voir les trois étapes principales : numérisation, recyclage et nettoyage.

Je pense que comparé à d'autres langages, le modèle de collecte des ordures dans Golang est relativement simple.

Problèmes dans gc

gc peut être considéré comme ayant été introduit pour résoudre le problème du recyclage de la mémoire. Lors de l'utilisation de langages nouvellement développés (java, python, php, etc.), les utilisateurs n'ont pas besoin de se soucier de la libération des objets de mémoire, mais doivent uniquement se soucier de l'application des objets en effectuant des opérations associées au moment de l'exécution ou dans la machine virtuelle. , Pour obtenir l'effet de gestion automatique de l'espace mémoire, ce comportement de recyclage automatique des ressources mémoire qui ne sont plus utilisées est appelé garbage collection.

Selon la déclaration précédente, le fait que gc puisse identifier correctement une référence est la base pour que gc fonctionne normalement. Par conséquent, la première question est de savoir comment gc doit identifier une référence ?

Le plus gros problème : il est difficile d'identifier les références, et le code machine est difficile de savoir ce qui compte comme référence. Si une référence est manquée par erreur, la mémoire qui n'était pas prête à être libérée le sera désormais par erreur, la stratégie consiste donc à pécher par excès de plus que de moins.

Une stratégie consiste à traiter tous les espaces mémoire comme des références possibles (valeurs de pointeur). C’est ce qu’on appelle un ramasse-miettes conservateur. C'est ainsi que fonctionne le garbage collector Boehm en C. C'est-à-dire que les variables ordinaires en mémoire sont traitées comme des pointeurs et tentent de couvrir tous les pointeurs. Si par hasard il y a d'autres objets dans l'espace pointés par la valeur de la variable ordinaire, alors cet objet ne sera pas recyclé. L'implémentation du langage go est pleinement consciente des informations de type de l'objet et ne traversera que l'objet pointé par le pointeur lors du marquage, évitant ainsi le gaspillage de mémoire tas dans l'implémentation C (résolution d'environ 10 à 30 %). Marquage tricolore

2014/6 1.3 Introduction du nettoyage simultané (exécution simultanée du garbage collection et de la logique utilisateur ?)

2015/8 1.5 Présentation du marquage tricolore

Concernant l'introduction du nettoyage simultané, reportez-vous à ici. Dans la version 1.3, le runtime go séparait les opérations de marquage et de balayage Comme auparavant, l'exécution de toutes les tâches est d'abord suspendue et le marquage démarre (la partie marquage nécessite toujours l'original). programme arrêté), la tâche suspendue sera redémarrée immédiatement après la fin du marquage et la tâche de balayage sera exécutée en parallèle avec d'autres tâches de la même manière que les tâches de coroutine ordinaires. S'il fonctionne sur un processeur multicœur, go essaiera d'exécuter la tâche gc sur un cœur séparé sans affecter l'exécution du code métier. L'équipe go elle-même affirme qu'elle réduit le temps de pause de 50 à 70 %.

L'algorithme de base est le nettoyage + recyclage mentionné précédemment. Le cœur de l'optimisation de Golang gc est d'essayer de rendre le temps STW (Stop The World) de plus en plus court.

Comment mesurer GC

Après tant de choses déjà dit, comment mesurer l'efficacité des étoiles de gc et déterminer si elle a un impact sur le fonctionnement du programme ? La première consiste à définir les variables d'environnement de godebug. Pour plus de détails, vous pouvez vous référer à cet article : Lien, comme exécuter

. pour comprendre les principes de gc. Pour une analyse plus approfondie, l'avantage de cet article est qu'il comprend clairement les facteurs qui déterminent le temps gc de golang. Par conséquent, différentes méthodes peuvent être adoptées pour améliorer le temps gc :

. GODEBUG=gctrace=1 ./myserverSelon l'analyse précédente, nous pouvons également savoir que gc en golang utilise la méthode de marquage clair, donc le temps total de gc est :

(T représente le temps)

Tgc = Tseq + Tmark + Tsweep

Tseq représente le temps nécessaire pour arrêter la goroutine de l'utilisateur et effectuer certaines activités préparatoires (généralement petites)
  • Tmark est le temps de marquage du tas se produit lorsque toutes les goroutines de l'utilisateur sont arrêtées, cela peut donc affecter de manière significative. le délai de traitement
  • Tsweep est le temps de suppression du tas. La suppression se produit généralement en même temps que l'exécution normale du programme, elle n'est donc pas critique pour le délai
  • La granularité sera. subdivisé plus tard, et les concepts spécifiques sont encore quelque peu Je ne comprends pas très bien :

Lié à Tmark : 1 Pendant le processus de récupération de place, le nombre d'objets actifs dans le tas, 2 Le montant total de mémoire occupée par les objets actifs avec des pointeurs 3 Le nombre de pointeurs dans les objets actifs .
  • En rapport avec Tsweep : 1 La quantité totale de mémoire du tas 2 La quantité totale de déchets dans le tas
  • Comment effectuer le réglage gc (conférence Gopher Danny)

Paramètres durs

Lorsqu'il s'agit de problèmes d'algorithme, il y aura toujours certains paramètres. Le paramètre GOGC contrôle principalement l'utilisation de la mémoire

au démarrage du prochain gc.

Par exemple, le programme actuel utilise 4 Mo de mémoire (on parle ici de mémoire tas

), ce qui signifie que la mémoire actuellement accessible du programme est de 4 Mo lorsque la mémoire est occupée par. le programme atteint l'accessibilité* Lorsque (1+GOGC/100)=8M, gc sera déclenché et les opérations gc associées commenceront.

La manière de définir les paramètres GOGC doit être déterminée en fonction du scénario réel en production, par exemple en augmentant les paramètres GOGC pour réduire la fréquence de GC.

Conseils

Si vous souhaitez avoir des informations approfondies, c'est essentiel lors de l'utilisation de gdb. Cet article a compilé quelques conseils d'introduction à l'utilisation de gdb.

Réduire l'allocation d'objets

La soi-disant réduction de l'allocation d'objets signifie en fait réutiliser les objets autant que possible. Par exemple, les deux définitions de fonction suivantes :

La première fonction n'a pas de paramètres formels et renvoie un []byte à chaque fois qu'elle est appelée. La deuxième fonction a un paramètre formel de buf à chaque fois qu'elle est appelée. ]objet de type octet, renvoie ensuite le nombre d'octets lus.

La première fonction allouera un espace à chaque fois qu'elle sera appelée, ce qui entraînera une pression supplémentaire sur gc. La deuxième fonction réutilisera la déclaration formelle des paramètres à chaque fois qu'elle sera appelée.

Un discours banal sur la conversion de chaîne et de []octet

La conversion entre chaîne et []octet mettra la pression sur gc Grâce à gdb, vous pouvez d'abord comparer les structures de données des deux :

Lorsque les deux sont convertis, la structure de données sous-jacente sera copiée, donc l'efficacité du gc deviendra inférieure. En termes de stratégie de solution, une solution consiste à toujours utiliser []byte, en particulier en termes de transmission de données, []byte contient également de nombreuses opérations efficaces couramment utilisées dans les chaînes. L'autre consiste à utiliser des opérations de niveau inférieur pour convertir directement afin d'éviter la copie. Vous pouvez vous référer à la première partie de l'optimisation des performances dans WeChat « Yuhen Academy », qui utilise principalement unsafe.Pointer pour la conversion directe.

Concernant l'utilisation de unsafe, je pense que je peux compiler un article séparé. Tout d'abord, répertoriez les informations pertinentes ici http://studygolang.com/articles/685 Intuitivement, vous pouvez comprendre unsafe.Pointer Into void. * en C++, en golang, c'est l'équivalent d'un pont de conversion de différents types de pointeurs.

Le type sous-jacent de uintptr est int, qui peut contenir la valeur de l'adresse pointée par le pointeur. Il peut être converti vers et depuis unsafe.Pointer. La principale différence est que uintptr peut participer aux opérations de pointeur, tandis qu'unsafe.Pointer ne peut effectuer que la conversion de pointeur et ne peut pas effectuer d'opérations de pointeur. Si vous souhaitez utiliser Golang pour l'arithmétique des pointeurs, vous pouvez vous y référer. Lors de l'exécution d'opérations de pointeur spécifiques, il doit d'abord être converti en type uintptr avant de pouvoir effectuer d'autres calculs, tels que le décalage, etc.

Utilisez + avec parcimonie pour connecter une chaîne Puisque l'utilisation de + pour connecter des chaînes générera de nouveaux objets et réduira l'efficacité de gc, le meilleur moyen est d'utiliser la fonction append.

Mais il y a un autre inconvénient. Par exemple, référez-vous au code suivant :

Après avoir utilisé l'opération append, l'espace du tableau augmente de 1024 à 1312, donc si la longueur du tableau tableau peut être connu à l'avance, il est préférable de le faire. Heureusement, la planification de l'espace est effectuée lorsque l'espace est initialement alloué, ce qui augmentera certains coûts de gestion du code, tout en réduisant la pression sur gc et en améliorant l'efficacité du code.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer