Maison >Java >javaDidacticiel >Comprendre le mécanisme de récupération de place Java
Avant de parler des jeux de mémoire et des listes de cartes, permettez-moi d'abord de vous présenter la question de la référence intergénérationnelle.
Supposons que vous souhaitiez effectuer une collecte (GC Mineur) limitée à la zone de nouvelle génération, mais que l'objet instance 1 de la nouvelle génération soit référencé dans l'ancienne génération, afin de connaître tous les objets de cette zone (nouvelle génération) Les objets survivants doivent traverser tous les objets de l'ancienne génération entière en plus des racines GC fixes pour garantir l'exactitude des résultats de l'analyse d'accessibilité, et vice versa. Bien que la solution consistant à parcourir tous les objets de l'ensemble de l'ancienne génération soit théoriquement réalisable, elle entraînera sans aucun doute une lourde charge de performances pour le recyclage de la mémoire.
En fait, ce n'est pas seulement le problème des références intergénérationnelles entre la nouvelle génération et l'ancienne génération. Tous les garbage collector impliqués dans le comportement de collecte de zone partielle (Partial GC), généralement tels que les collecteurs G1, ZGC et Shenandoah, le feront. faites-y face.
Tout d’abord, les citations intergénérationnelles ne représentent qu’un très petit nombre par rapport aux citations de même génération. La raison en est que les objets référencés à travers les générations devraient avoir tendance à survivre ou à mourir en même temps (par exemple : si un objet de nouvelle génération a une référence entre générations, parce que l'objet de l'ancienne génération est difficile à mourir, cette référence permettra au nouveau objet de génération à collecter lorsqu'il est collecté. Survivre, puis être promu à l'ancienne génération à mesure qu'il vieillit, date à laquelle les références intergénérationnelles sont également éliminées).
D'après ce qui est dit ci-dessus, il n'est pas nécessaire de scanner toute l'ancienne génération pour un petit nombre de références intergénérationnelles. Il n'est pas nécessaire de perdre de l'espace pour enregistrer si chaque objet existe et quelles références intergénérations existent. Il vous suffit d'en établir une globale sur la nouvelle génération. Une structure de données (cette structure est appelée "Remembered Set"). Cette structure divise l'ancienne génération en plusieurs petits blocs et identifie quel morceau de mémoire l'ancienne génération aura. références transgénérationnelles. Par la suite, lorsque Minor GC se produit, seuls les objets situés dans de petits blocs de mémoire contenant des références intergénérationnelles seront ajoutés à GCRoots pour analyse. Bien que cette méthode doive maintenir l'exactitude des données enregistrées lorsque l'objet change sa relation de référence (comme s'attribuer lui-même ou un certain attribut), ce qui augmentera une certaine surcharge d'exécution, elle reste plus rentable que d'analyser l'intégralité de l'ancienne génération. lors de la collecte de.
Ce qui suit est une introduction à cet ensemble de mémoire de structure de données globale.
L'ensemble de mémoire est une structure de données abstraite utilisée pour enregistrer une collection de pointeurs depuis des zones de non-collecte vers des zones de collection. Si nous ne prenons pas en compte l'efficacité et le coût, l'implémentation la plus simple peut utiliser tous les tableaux d'objets contenant des références de génération croisée dans la zone de non-collection pour implémenter cette structure de données, comme le montre le code suivant :
//以对象指针来实现记忆集的伪代码 Class RememberedSet { Object[] set[OBJECT_INTERGENERATIONAL_REFERENCE_SIZE]; }
Tous ces enregistrements contiennent des références de génération La solution d'implémentation d'objet est assez coûteuse en termes d'occupation de l'espace et de coût de maintenance. Dans un scénario de garbage collection, le collecteur n'a besoin que d'utiliser l'ensemble de mémoire pour déterminer si une certaine zone de non-collecte possède un pointeur pointant vers la zone de collecte. Il n'a pas besoin de connaître tous les détails de ces pointeurs inter-générations. Lorsque les concepteurs implémentent l’ensemble de mémoire, ils peuvent choisir une granularité d’enregistrement plus grossière pour économiser les coûts de stockage et de maintenance de l’ensemble de mémoire. Vous trouverez ci-dessous quelques précisions d'enregistrement parmi lesquelles choisir (bien sûr, vous pouvez également choisir en dehors de cette plage) :
Précision de la longueur des mots : chaque enregistrement est précis à une longueur de mot machine (c'est-à-dire le nombre de bits d'adressage du processeur , comme commun de 32 ou 64 bits, cette précision détermine la longueur des pointeurs utilisés par la machine pour accéder aux adresses mémoire physiques), ce mot contient des pointeurs de croisement de générations.
Précision de l'objet : chaque enregistrement est précis par rapport à un objet, et certains champs dans l'objet contiennent des pointeurs inter-générations.
Précision de la carte : chaque enregistrement est précis par rapport à une zone de mémoire, et certains objets dans cette zone contiennent des pointeurs inter-générations.
Le troisième type de « précision de carte » ci-dessus fait référence à l'utilisation d'une méthode appelée « Table de cartes » pour implémenter des ensembles de mémoire, qui est également la forme d'implémentation d'ensembles de mémoire la plus couramment utilisée à l'heure actuelle.
Quelle est la relation entre la liste de cartes et l'ensemble de mémoire ?
Lorsque j'ai présenté l'ensemble de mémoire plus tôt, j'ai mentionné que l'ensemble de mémoire est en fait une structure de données "abstraite". L'abstraction signifie qu'elle définit uniquement l'intention comportementale de l'ensemble de mémoire et ne définit pas l'implémentation spécifique de son comportement. La table de cartes est une implémentation spécifique de l'ensemble de mémoire, qui définit la précision d'enregistrement de l'ensemble de mémoire, la relation de mappage avec la mémoire tas, etc. Concernant la relation entre l'ensemble de mémoire et la table de cartes, elle peut être comprise par analogie avec la relation entre Map et HashMap en Java (c'est-à-dire la relation entre l'interface et la classe d'implémentation).
Parlons en détail de l'implémentation spécifique de la table des cartes de jeu de mémoire
La table des cartes est implémentée à l'aide d'un tableau d'octets CARD_TABLE[]. il identifie. Chaque élément Un bloc mémoire est appelé une page de carte. La page de carte utilisée par hotspot fait 2 ^ 9 ou 512 octets. Comme le montre la figure ci-dessous
De cette façon, nous pouvons diviser une certaine zone en fonction des pages de cartes. Si nous voulons maintenant effectuer le ramassage des ordures sur la zone de nouvelle génération, alors nous pouvons considérer la zone de l'ancienne génération comme une seule. page de carte et une carte. Les pages sont divisées comme indiqué dans la figure ci-dessous.
Comme le montre la figure, comme il existe une référence intergénérationnelle pointant vers la nouvelle génération dans cardpage1, la première position de la table de cartes correspondante est 1, indiquant qu'il existe des objets d'application intergénérationnels dans cette zone de page. .
Angle de la table à cartes : comme il y a des objets à boire multi-générations dans la page 1, la première position correspondant à la table à cartes est enregistrée comme 1, indiquant que l'élément page1 est sale.
Angle de recyclage de la mémoire : étant donné que la première position de la table à cartes est 1, cela indique qu'il y a des objets d'application intergénérationnels dans la zone de la page et que cette zone doit être analysée lors du ramassage des ordures.
La mémoire d'une page de carte contient généralement plus d'un objet. Tant qu'il y a un pointeur de génération croisée dans le champ d'un (ou plusieurs) objets dans la page de carte, la valeur de l'élément de tableau de la page de carte. la table de cartes correspondante sera marquée par 1 , cet élément est appelé sale (Dirty), sinon, il est marqué par 0. Lorsque le garbage collection se produit, tant que les éléments sales de la table de cartes sont filtrés, vous pouvez facilement découvrir quels blocs de mémoire de page de carte contiennent des pointeurs intergénérationnels, les ajouter aux racines GC et les analyser ensemble. Cela élimine le besoin d’analyser l’intégralité de l’ancienne génération et réduit considérablement la plage d’analyse des racines GC.
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!