Lorsque nous écrivons du code Java, dans la plupart des cas, nous n'avons pas besoin de nous soucier de savoir si ou quand votre nouvel objet est publié. Parce qu'il existe un mécanisme automatique de récupération de place dans la JVM. Dans le blog précédent, nous avons parlé des méthodes de gestion de la mémoire de MRC (comptage manuel de références) et ARC (comptage automatique de références) en Objective-C, ci-dessous Je vais l'examiner. Le mécanisme actuel de recyclage de la mémoire JVM n'utilise pas de comptage de références, mais utilise principalement le « recyclage de copie » et le « recyclage adaptatif ».
Bien sûr, en plus des deux algorithmes ci-dessus, il existe d'autres algorithmes, qui seront également présentés ci-dessous. Dans ce blog, nous parlerons d'abord brièvement de la division régionale de la JVM, puis présenterons le mécanisme de collecte des ordures de la JVM sur cette base.
1. Brève description de la division de la zone mémoire JVM
Bien sûr, cette partie est une brève discussion. Examinons la division de la zone mémoire de la JVM pour ouvrir la voie à l'expansion du mécanisme de récupération de place ci-dessous. Bien sûr, il existe de nombreuses informations détaillées sur la division des zones de mémoire JVM sur Internet, veuillez les rechercher vous-même sur Google.
Sur la base de la division de la zone mémoire JVM, j'ai simplement dessiné le schéma ci-dessous. La zone est principalement divisée en deux grands blocs. L'un est Heap Les objets que nous créons seront alloués dans la zone du tas. La méthode d'allocation de malloc en langage C consiste à l'obtenir à partir de la zone du tas. . Le garbage collector recycle principalement la mémoire dans la zone du tas.
L'autre partie est la zone non tas La zone non tas comprend principalement la "zone de cache de code (Cache de code)" utilisée pour compiler et sauvegarder. code local. La "Génération éternelle (Perm Gen)" qui enregistre les propres données statiques de la JVM, la "Java Virtual Machine Stack (JVM Stack) qui stocke les références aux paramètres de méthode et locaux. variables et enregistre l'ordre des appels de méthode » et « Local Method Stack (Local Method Stack) ».
Le garbage collector récupère principalement les zones mémoire inutilisées dans la zone du tas et organise les zones correspondantes. Dans la zone du tas, il est divisé en « jeune génération » et « ancienne génération » en fonction du temps de survie de la mémoire de l'objet ou de la taille de l'objet. Les objets de la « jeune génération » sont instableset sujets aux déchets, tandis que les objets de « l'ancienne génération » sont relativement stables et moins sujets aux déchets. La raison pour laquelle ils sont séparés est de diviser pour régner. Selon les caractéristiques des blocs de mémoire dans différentes zones, différents algorithmes de récupération de mémoire sont adoptés pour améliorer l'efficacité du garbage collection dans la zone du tas. Une introduction détaillée sera donnée ci-dessous.
2. Introduction aux algorithmes courants de recyclage de mémoire
Nous avons une brève compréhension de la Division des zones de mémoire dans JVM ci-dessus, examinons ensuite plusieurs algorithmes courants de recyclage de mémoire. Bien entendu, l'algorithme de recyclage de mémoire présenté ci-dessous n'est pas seulement utilisé dans JVM, nous passerons également en revue la méthode de recyclage de mémoire dans OC. Ci-dessous figurent principalement le « recyclage par comptage de référence », le « recyclage des copies », le « recyclage par tri marqué » et le « recyclage générationnel ».
1. Recyclage de la mémoire de comptage de références
Compte de références (Compte de références) La mémoire Le mécanisme de recyclage est le mécanisme de recyclage de la mémoire actuellement utilisé dans les langages Objective-C et Swift Dans les blogs précédents, nous avons également parlé en détail du recyclage de la mémoire par comptage de références. Tant qu'il y a une référence, le nombre de références est augmenté de 1. Lorsque le compteur de référence atteint 0, le bloc de mémoire sera recyclé. Bien entendu, cette méthode de nettoyage de mémoire peut facilement former un « cycle de référence ».
Les références circulaires dans le décompte de références de Objective-C provoquent des fuites de mémoire. Les variables peuvent être déclarées comme des types faibles ou forts. C'est-à-dire que l'on peut définir la référence comme « Référence forte » ou « Référence faible ». Lorsque "Cycle de référence fort" apparaît, nous pouvons définir l'une des références sur type faible, et alors ce cycle de référence fort sera rompu, et il n'y aura pas de "Fuite de mémoire" problème. Pour des informations de plus en plus détaillées sur le « Recyclage de la mémoire comptée par référence », veuillez vous référer aux blogs connexes publiés précédemment sur le contenu OC.
Afin de comprendre plus clairement comment fonctionne le comptage de références, j'ai simplement dessiné l'image ci-dessous. Les trois références a, b et c dans la pile de gauche pointent vers différents blocs de zone dans le tas. Dans un bloc de zone mémoire du tas, lorsqu'il y a une forte référence à cette zone, son retentionCount sera augmenté de 1. Lorsque référence faiblement , le retentionCount ne sera pas augmenté de 1.
Regardons d'abord la première zone mémoire référencée par a. Parce que seul a est fortement référencé dans ce bloc mémoire, retentionCount=1 Lorsque a ne fait plus référence à cette zone mémoire, retentionCount=0, et. la mémoire Comprendra être recyclée. Dans ce cas, il n’y aura pas de fuite de mémoire.
Jetons un coup d'œil à la zone mémoire 2 pointée par b. b et le bloc mémoire 3 ont tous deux de fortes références au bloc mémoire 2, donc 2 retainCount=2. Le bloc de mémoire 2 a également une forte référence au bloc de mémoire 3, donc 3's retentionCount=1. Il existe donc un "cycle de référence fort" dans la zone mémoire pointée par b, car lorsque b ne pointe plus vers cette zone mémoire, rc=2 deviendra rc=1. Parce que holdCount n'est pas nul, ces deux zones mémoire ne seront pas libérées, et 2 ne seront pas libérées, donc naturellement les trois zones mémoire ne seront pas libérées, mais cette zone mémoire ne sera plus utilisée, donc cela provoquera un ". Fuite de mémoire". Si ces deux zones mémoire sont particulièrement volumineuses, alors on peut imaginer que les conséquences seront lourdes.
Une situation comme c référence ne provoquera pas de "cycle de référence fort" car l'une des chaînes de référence est une référence faible. Lorsque c ne fait plus référence au quatrième bloc de mémoire, rc passe de 1 à zéro, alors la zone de bloc sera immédiatement libérée. Une fois le bloc mémoire 4 libéré, le rc du bloc mémoire 5 passe de 1 à 0 et le bloc mémoire 5 sera également libéré. Dans ce cas, aucune fuite de mémoire ne se produira. C'est la méthode utilisée pour recycler la mémoire en Objective-C Bien sûr, en OC, en plus de la "référence forte" et de la "référence faible", il existe également un pool de libération automatique. En d'autres termes, la référence de type Autorealease ne sera pas publiée immédiatement lorsque retentionCount = 0, mais sera publiée lorsqu'elle sortira du pool de libération automatique. Je n'entrerai pas dans les détails ici.
2. Recyclage de la mémoire de copie
Après avoir parlé du recyclage du comptage de références , nous savons que le comptage de références peut facilement provoquer des problèmes de « référence cyclique ». Afin de résoudre le problème de fuite de mémoire provoqué par la « référence cyclique », les concepts de « référence forte » et de « référence faible » sont introduits. en OC. Nous examinerons ensuite le mécanisme de recyclage de la mémoire de copie. Dans ce mécanisme, il n'y a pas lieu de s'inquiéter de la question des « références cycliques ». En termes simples, le cœur du recyclage basé sur la copie est la « copie », mais le principe est la copie conditionnelle. Lors du garbage collection, les « objets actifs » sont copiés dans une autre zone de tas vide, puis la zone précédente est effacée ensemble. Les « objets actifs » font référence aux objets qui peuvent être atteints sur la « pile » le long de la chaîne de référence de l'objet. Bien entendu, après avoir copié l'objet actif dans la nouvelle "zone de tas", la référence à la zone de pile doit également être modifiée.
Vous trouverez ci-dessous un schéma simplifié du recyclage de type copie que nous avons dessiné. Il divise principalement le tas en deux parties. Lors du garbage collection, les objets vivants sur un tas seront copiés sur un autre tas. La zone du tas 1 ci-dessous est le bloc actuellement utilisé et la zone du tas 2 est la zone libre. Les blocs de mémoire non marqués dans la zone de tas 1, c'est-à-dire 2 et 3, sont des objets inutiles à recycler. Et 1, 4 et 5 sont des « objets vivants » à copier. Parce que le bloc 1 peut être atteint le long de a sur la pile, et les blocs 4 et 5 peuvent être atteints le long de c. Bien que les blocs 2 et 3 aient des références, ils ne proviennent pas de la zone hors tas , c'est-à-dire que les références des blocs 2 et 3 sont toutes deux des références de la zone du tas, ce sont donc des objets à recycler .
Après avoir trouvé l'objet vivant, la prochaine chose à faire est de copier l'objet vivant et de le copier dans la zone du tas 2. Bien entendu, les adresses mémoire entre les objets copiés dans la zone de tas 2 sont continues. Si vous souhaitez allouer un nouvel espace mémoire, vous pouvez l'allouer directement à partir d'une section libre du tas. Ceci est plus efficace lors de l’allocation de l’espace mémoire. Une fois l'objet copié, l'adresse de référence de la « zone non tas » doit être modifiée. Comme indiqué ci-dessous.
Une fois la copie terminée, nous pouvons directement recycler tout l'espace mémoire dans la zone de tas 2. Voici le résultat final après copie et recyclage. Une fois la zone de tas inférieure 1 effacée, les objets copiés peuvent être reçus. Lorsque le garbage collection est effectué sur la zone de tas 2, les objets actifs de la zone de tas 2 seront copiés dans la zone de tas 1.
À partir de cet exemple, nous pouvons voir que lorsqu'il y a beaucoup de déchets mémoire, l'efficacité du garbage collection "copie" est encore relativement élevée, car il y a relativement peu d'objets copiés et l'ancien espace de tas peut être nettoyé directement lors du nettoyage. Cependant, lorsqu'il y a relativement peu de déchets, cette méthode copiera un grand nombre d'objets vivants et l'efficacité sera encore relativement faible. Cette méthode divisera également l’espace de stockage du tas en deux. En d’autres termes, la moitié est toujours gratuite et le taux d’utilisation de l’espace du tas n’est pas élevé.
3. Algorithme de récupération par compression de marque
D'après ce qui précède 🎜 >Dans le processus de collecte des déchets « copie », nous savons que lorsqu'il y a beaucoup de déchets, l'efficacité est relativement élevée, mais lorsqu'il y a peu de déchets, l'efficacité de la méthode de travail est relativement faible. Nous présenterons donc ensuite un autre algorithme de recyclage de compression de marques. Cet algorithme est plus efficace lorsqu'il y a moins de déchets, mais lorsqu'il y a plus de déchets, l'efficacité n'est pas élevée. Ceci est similaire à "
Copier la formule " forme un complément. Ci-dessous, nous présenterons l'algorithme de recyclage par compression de marques.Marquage - La première étape de la compression est le marquage, qui nécessite de marquer les "objets vivants
" dans la zone du tas. Nous avons déjà parlé de ce qu'est un « objet vivant » dans le contenu ci-dessus, nous n'entrerons donc pas dans les détails ici. D'après les caractéristiques des "objets vivants", nous pouvons voir que les objets vivants ci-dessous sont les zones mémoire 1 et 3, nous les marquons donc.Une fois le marquage terminé, nous commençons à compresser, compressons les objets vivants dans une section de la « zone de tas », puis effaçons les parties restantes. Ci-dessous se trouve la compression des deux objets vivants 1 et 3. Après compression, nettoyez l'espace ci-dessous. Autrement dit, dans la partie Clean, de nouveaux objets peuvent être alloués.
La capture d'écran ci-dessous est marquée comme compressée et nettoyée. Le garbage collection compressé marqué peut utiliser pleinement l'espace dans la zone du tas. Lorsqu'il y a relativement peu de déchets, cette méthode de traitement est relativement efficace. S'il y a trop de déchets et une fragmentation importante, davantage d'« objets vivants » sont déplacés et. l'efficacité est relativement faible. Cette méthode peut être utilisée conjointement avec « copie » pour sélectionner la méthode de recyclage basée sur l'état actuel des déchets de la zone du tas. Il complète les avantages de la « copie » . L'algorithme qui intègre les méthodes de recyclage « copie » et « marquage-compression » est le mécanisme de collecte des ordures « générationnel »
, qui sera présenté en détail ci-dessous.
4. Collecte des déchets générationnelle
"Génération
" signifie diviser les objets en différentes générations en fonction de leur propension à la génération de déchets ou de la taille de l'objet, qui peut être divisée en "jeune génération", "ancienne génération" et "génération permanente". La « génération permanente » n’est pas dans le tas, nous n’en reparlerons donc pas. Sur la base des caractéristiques du garbage collection générationnel, le diagramme simplifié suivant est dessiné.Dans le tas, les zones sont principalement divisées en « jeune génération » et « vieille génération ». La mémoire des objets situés dans la « jeune génération » ne prend pas longtemps à créer, est mise à jour relativement rapidement et est sujette aux « déchets de mémoire ». Par conséquent, la méthode de recyclage de « copie » pour la collecte des ordures dans la « jeune génération » est plus efficace. La « jeune génération » peut être divisée en deux zones, l'une est Eden Space (Eden Garden) et Survivor Sprace (zone des survivants) . Eden Space stocke principalement les objets créés pour la première fois, tandis que Survivor Sprace stocke les "objets vivants" qui ont survécu à Eden Space
. Le Survivor Sprace (zone des survivants) est divisé en deux blocs : form et to, qui sont utilisés pour copier des objets les uns sur les autres pour le nettoyage des déchets.L'"ancienne génération" stocke certains "gros objets" et "objets" qui ont survécu au Survivor Sprace
Généralement, les objets de "l'ancienne génération" sont relativement stables, générant moins. Dans ce cas, il est plus efficace d'utiliser la méthode de recyclage "mark-compression". Le « ramassage des ordures générationnel » divise et conquiert principalement, en classant différents objets en fonction de leurs caractéristiques et en sélectionnant des solutions de ramassage des ordures appropriées en fonction des caractéristiques de la classification.
3. Le principe de fonctionnement spécifique du ramassage des ordures générationnel
Bien sûr, dans le garbage collection spécifique de JVM, selon les threads, il peut être divisé en "Serial Garbage Collection" qui utilise un seul thread pour le recyclage, et "Parallel Garbage Collection ". Selon le statut de suspension du programme, celui-ci peut être divisé en « Recyclage exclusif » et « Recyclage simultané ». Bien sûr, nous en avons déjà parlé à plusieurs reprises. « Parallèle » et « concurrence » ne sont certainement pas les mêmes concepts, et il ne faut pas les confondre. Ce blog ne détaillera pas les méthodes ci-dessus. Si vous êtes intéressé, veuillez les rechercher sur Google.
Jetons un coup d'œil aux étapes complètes du principe de fonctionnement spécifique du « garbage collection générationnel » pour ressentir intuitivement la méthode d'exécution du garbage collection « générationnel ».1. Avant la collecte des ordures
L'image ci-dessous attend "la collecte des ordures générationnelle "Sur l'image ci-dessous, nous pouvons voir qu'une partie de la mémoire objet allouée dans le tas n'est pas référencée sur la pile. Ce sont les objets à recycler. Nous pouvons voir que le tas ci-dessous est divisé en « jeune génération » et « vieille génération » dans son ensemble, et la jeune génération peut être subdivisée en trois zones : Eden Space, From et To. Concernant le rôle de chaque zone, nous l'avons déjà introduit lors de l'introduction du « garbage collection générationnel » ci-dessus, nous ne le présenterons donc pas en détail dans cette partie.
2. Collecte des déchets générationnelle
L'image suivante est une comparaison de ce qui précède Le processus de récupération de place du contrôle du tas. Comme nous pouvons le voir sur l'image ci-dessus, la zone Vers est une zone vide et peut accepter des objets copiés. Étant donné que la « jeune génération » est encline à générer des déchets de mémoire, une méthode de recyclage de mémoire par « copie » est adoptée. Nous copions les "objets vivants" dans les deux blocs de tasEden Space et From dans la zone To. Lors de la copie, nous devons également modifier l'adresse de référence de pile de la mémoire copiée. L'espace de stockage « gros objets » de la zone From ou Eden est directement copié sur « l'ancienne génération ». Étant donné que l'efficacité des copies multiples de « gros objets » dans les zones De et Vers est relativement faible, ajoutez-les directement à « l'ancienne génération » pour améliorer l'efficacité du recyclage.
Pour le garbage collection "ancienne génération", le garbage collection "mark-compression" est utilisé. Dans un premier temps, les objets vivants sont « marqués ».3. Le résultat après ramassage des ordures
Ci-dessous le " points de résultats spécifiques à la « génération » après le garbage collection. D'après le diagramme ci-dessous, nous pouvons voir que les objets vivants dans Eden Space et From sont copiés dans la zone To, et l'espace de stockage de la zone de tas « ancienne génération » a également beaucoup changé. De plus, il y a plus d'objets volumineux copiés depuis la zone From dans "l'ancienne génération". Les détails sont les suivants.4. Configuration et analyse du journal Eclipse GC
Tant de choses ont été dites ci-dessus, découvrons intuitivement comment afficher le processus de récupération de place et analyser les informations du journal de récupération de place dans Eclipse. Par défaut, le processus de récupération de place et l'impression du journal ne sont pas affichés. Vous devez ajouter les éléments de configuration pertinents dans la configuration en cours pour imprimer le journal de récupération de place. Dans cette section, nous examinons la configuration de la journalisation du garbage collection dansEclipse, puis nous analysons ces enregistrements de journaux. Bien sûr, nous utilisons Java8 dans ce blog. Si vous utilisez d'autres versions de Java, les informations du journal imprimées seront légèrement différentes, alors commençons par cette partie.
1. Configurez les paramètres d'exécution d'Eclipse
Ajoutez les éléments de configuration correspondants dans les paramètres d'exécution d'Eclipse, qui ne seront imprimés qu'après garbage collection. Informations de journal correspondantes. Sélectionnez notre projet, puis recherchez l'optionExécuter les configurations... pour effectuer la configuration d'exécution.
Ci-dessous se trouve la boîte de dialogue ouverte par l'option ci-dessus, puis recherchez la barre d'onglets (x) = Arguments, ajoutez les paramètres de machine virtuelle correspondants dans Arguments VM, ces paramètres seront être utilisés comme paramètres du projet au moment de l'exécution. Ci-dessous, nous avons ajouté deux paramètres : -XX:+PrintGCTimeStamps et -XX:+PrintGCDetails. À partir de ces deux noms de paramètres, il n'est pas difficile de voir les fonctions correspondant aux paramètres correspondants. L'une consiste à imprimer l'horodatage du garbage collection et l'autre à imprimer les détails du garbage collection. Bien sûr, il existe de nombreux autres paramètres, tels que les paramètres de l'algorithme spécifique lors de la sélection du "garbage collection", et les paramètres permettant de choisir "série" ou "parallèle", et certains s'il faut choisir "exclusif" ou "simultané". " poubelle. Paramètres recyclés. Je n’entrerai pas dans les détails ici, veuillez le rechercher vous-même sur Google.
2. Impression et analyse des journaux de recyclage
Après avoir configuré le ci-dessus Après les paramètres, lorsque nous utilisons System.gc(); pour effectuer un garbage collection forcé, les informations sur les paramètres correspondants seront imprimées. Nous devons d’abord créer le code pour les tests. Vous trouverez ci-dessous la classe de test que nous avons créée. Bien entendu, le code de la classe de test est relativement simple. L'essentiel est de renouveller la chaîne, puis de définir la référence sur null, et enfin d'appeler System.gc() pour le recyclage. Le code spécifique est le suivant :
package com.zeluli.gclog;public class GCLogTest {public static void main(String[] args) { String s = new String("Value"); s = null; System.gc(); } }
Ce qui suit est l'effet du code ci-dessus. Ensuite, nous présenterons le contenu principal des informations du journal. ci-dessous. > >
PSYoungGen indique que la « jeune génération » est recyclée en parallèle 1997K->416K indique « avant recyclage->après recyclage » dans le correspondant. zone de la jeune génération ", tandis que (38400K) représente la taille totale du tas "jeune génération". Les données 1997K->424K (125952K) à l'arrière constituent un problème vu du point de vue de l'ensemble du tas. 1997 Ko (mémoire utilisée avant le recyclage du tas) -> 424 Ko (mémoire utilisée après le recyclage du tas) (125952 Ko - l'espace mémoire total du tas).
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!