copier l'algorithme
Pour plus de contenu de blog, visitez uniquement l'amour pour manger des fruits du dragon , cliquez pour en savoir plus
- aperçu
L'algorithme de copie divise la mémoire en deux intervalles . À tout moment, tous les objets alloués dynamiquement ne peuvent être alloués que dans l'un des intervalles (appelé intervalle actif), tandis que l'autre intervalle (appelé intervalle libre) est libre.
Lorsque l'espace mémoire effectif est épuisé, la JVM suspend l'exécution du programme et démarre le thread GC de l'algorithme de copie. Ensuite, le thread GC copiera tous les objets survivants de la zone active dans la zone libre et les organisera strictement en fonction des adresses mémoire. En même temps, le thread GC mettra à jour l'adresse de référence mémoire des objets survivants pour pointer à la nouvelle adresse mémoire.
- Avantages de l'algorithme de réplication
- Pour assurer la continuité de l'espace, il n'y aura pas de problème de "fragmentation".
- Aucune marque et processus clair, facile à mettre en œuvre et efficace à exécuter
- Optimisation de l'algorithme de réplication
La mémoire est divisée en 1 zone Eden et 2 zones Survivor . La zone Eden occupe 80 % de l'espace mémoire et chaque zone Survivor occupe 10 % de l'espace mémoire. Par exemple, la zone Eden dispose de 800 Mo de mémoire et chaque zone Survivor zone dispose de 100 Mo de mémoire.
Dans la zone Survivor, l'un s'appelle From et l'autre s'appelle To, et des objets existent dans les blocs Eden et From. Lorsque GC est effectué, tous les objets survivants dans Eden sont déplacés vers le bloc To, tandis que dans From, les objets survivants sont déterminés en fonction de la valeur d'âge. Lorsque l'objet atteint une certaine valeur, il sera déplacé vers l'ancienne génération, et l'objet qui n'a pas atteint la valeur est copié dans le bloc To. , après que GC, Eden et From soient vidés. Après cela, From et To échangent des rôles, le nouveau From est le bloc To d'origine, le nouveau bloc To est le bloc From d'origine et l'âge de l'objet dans le nouveau bloc To est augmenté de 1.
Remarque : Le seuil d'âge peut être défini par -XX:MaxTenuringThreshold
Processus MinorGC
- Moment de déclenchement :
Il se déclenchera lorsque la zone Eden sera pleine, mais la zone Survivor ne déclenchera pas GC
- expliquer
Lors de l'exécution du code, divers objets seront continuellement créés, et ces objets seront préférentiellement placés dans la zone Eden et la zone Survivor1 de la nouvelle génération.
Si la zone Eden et la zone Survivor1 de la nouvelle génération sont presque pleines , le GC mineur sera déclenché à ce moment pour transférer les objets survivants vers la zone Survivor2. À ce moment, tous les objets survivants dans la zone Eden seront transférés dans une zone Survivor vide en une seule fois. Ensuite, la zone d'Eden sera nettoyée.
Ensuite, attribuez à nouveau de nouveaux objets à la zone Eden. Il y a des objets dans la zone Eden et une zone Survivor. La zone Survivor contient des objets qui ont survécu au dernier GC mineur. Si la zone Eden est à nouveau pleine la prochaine fois, le GC mineur est à nouveau déclenché, et les objets survivants dans la zone Eden et la zone Survivor où les objets survivants après le dernier GC mineur sont placés seront transférés vers une autre zone Survivor.
Lorsqu'un objet entre dans l'ancienne génération
Selon l'âge cible
Chaque fois qu'un objet s'échappe de MinorGC dans la nouvelle génération et est transféré dans une zone Survivor, son âge augmentera d'un an. Par défaut, lorsque l'objet atteint 15 ans, il en évitera 15 Au prochain GC, il sera transféré à l'ancienne génération . L'âge spécifique auquel un enfant entre dans la vieillesse peut être défini via le paramètre JVM "-XX:MaxTenuringThreshold", et la valeur par défaut est de 15 ans.
Jugement dynamique de l'âge de l'objet
Il existe une autre règle qui permet aux objets d'entrer dans la vieillesse sans attendre que 15 GC soient passés.
Dans la zone Survivant courante, si la taille totale d'un lot d'objets dépasse 50% de la taille mémoire de cette zone Survivant, alors les objets dont l'âge est supérieur ou égal à l'âge de ce lot d'objets peuvent entrer directement dans l'ancien âge.
Supposons qu'il y ait trois objets dans la zone Survivor2 dans cette figure. L'âge de ces objets est le même, ils ont tous 3 ans et les objets combinés des deux objets dépassent 50 Mo, soit plus de la moitié de la mémoire de 100 Mo. taille de la zone Survivant 2. A ce moment, la zone Survivor 2 Les objets âgés de 3 ans ou plus entreront tous dans l'ancienne génération. Il s'agit de la règle dite du jugement d'âge dynamique, et cette règle permettra également à certains objets de la nouvelle génération d'entrer dans la vieillesse.
De plus, voici un concept à clarifier, c'est-à-dire que la logique réelle de cette règle est la suivante : la somme des objets d'âge multiples d'âge 1+âge 2+âge n dépasse 50 % de la zone Survivant. Les objets sont placés dans l'ancienne génération .
Les gros objets vont directement à l'ancienne génération
Il existe un paramètre JVM, qui est " -XX:PretenureSizeThreshold ", qui peut définir sa valeur sur le nombre d'octets, tel que "1048576" octets, soit 1 Mo. Cela signifie que si vous souhaitez créer un objet plus grand que cette taille, comme un super grand tableau, ou autre chose, vous pouvez directement mettre ce grand objet dans l'ancienne génération à ce moment. ne passera pas par la nouvelle génération. La raison en est d'éviter l'apparition d'objets aussi volumineux dans la nouvelle génération, puis d'éviter à plusieurs reprises GC, puis de copier plusieurs fois entre les deux zones Survivor avant d'entrer dans l'ancienne génération.
Trop d'objets après Minor GC
Après le GC mineur, on constate qu'il reste trop d'objets survivants, et qu'il n'y a aucun moyen de les mettre dans une autre zone Survivor.À ce moment, ces objets doivent être directement transférés à l'ancienne génération.
Règles de Garantie d'Allocation d'Espace Ancienne Génération
- la question mène
Si un grand nombre d'objets survivent dans la nouvelle génération, il est vrai que la zone Survivor ne peut pas les accueillir et doit être transférée à l'ancienne génération, alors que se passe-t-il s'il n'y a pas assez d'espace dans l'ancienne génération pour stocker ces objets ?
- résoudre
Tout d'abord, avant d'exécuter un GC mineur, la JVM vérifiera d'abord si l'espace mémoire disponible disponible dans l'ancienne génération est supérieur à la taille totale de tous les objets de la nouvelle génération. Pour éviter la situation la plus extrême, tous les objets peuvent survivre au GC mineur dans la nouvelle génération, et tous les objets de la nouvelle génération entreront dans l'ancienne génération.
S'il s'avère que la taille de la mémoire de l'ancienne génération est plus grande que tous les objets de la nouvelle génération, un GC mineur peut être lancé sur la nouvelle génération à ce moment, car même si tous les objets survivent après le GC mineur, le survivant zone ne peut plus s'adapter, et ils peuvent être transférés à l'ancienne génération.
Si avant d'exécuter Minor GC, il s'avère que la mémoire disponible dans l'ancienne génération est inférieure à la taille de tous les objets de la nouvelle génération, alors à ce moment, il est possible que tous les objets de la nouvelle génération survivent après le Minor GC, puis tous doivent être transférés à l'ancienne génération, mais l'ancienne génération L'espace d'âge ne suffit pas. Donc, s'il est avant Minor GC, il vérifiera si un paramètre "-XX:-HandlePromotionFailure" est défini. S'il existe ce paramètre, il continuera à essayer de faire le prochain jugement.
- Vérifiez si la taille de la mémoire de l'ancienne génération est supérieure à la taille moyenne des objets entrant dans l'ancienne génération après chaque GC mineur.
Par exemple : après chaque GC mineur, une moyenne d'environ 10 Mo d'objets entrera dans l'ancienne génération, donc la mémoire disponible dans l'ancienne génération à ce moment est supérieure à 10 Mo. Cela signifie qu'il est très probable que des objets d'environ 10 Mo entreront dans l'ancienne génération après le GC mineur. A ce moment, l'espace dans l'ancienne génération est suffisant et peut être recyclé.
- Si le jugement de l'étape ci-dessus échoue, ou si le paramètre "-XX:-HandlePromotionFailure" n'est pas défini, un "Full GC" sera déclenché directement à ce moment, qui consiste à effectuer un ramasse-miettes sur l'ancienne génération, essayez de libérer de l'espace mémoire, puis effectuez un GC mineur.
- Résumer
Avant que le GC mineur ne se produise, la machine virtuelle vérifie si l'espace continu disponible maximal dans l'ancienne génération est supérieur à l'espace total de tous les objets de la nouvelle génération.
- S'il est supérieur à, ce GC mineur est sûr
- Si elle est inférieure à, la machine virtuelle vérifiera si la valeur du paramètre -XX:-HandlePromotionFailure est autorisée à faire échouer la garantie.
- Si HandlePromotionFailure=true, il continuera à vérifier si l'espace continu maximum disponible dans l'ancienne génération est supérieur à la taille moyenne des objets promus à l'ancienne génération
- S'il est plus grand, essayez d'effectuer un GC mineur, mais ce GC mineur est toujours risqué ; si l'objet survivant est plus grand que la taille de la zone Survivor après recyclage, et qu'il est également plus grand que la taille de la mémoire disponible dans le ancienne génération, "Handle Promotion Failure" se produira Dans ce cas, un "Full GC" sera déclenché à ce moment
- S'il est inférieur à cela, effectuez plutôt un GC complet.
- Si HandlePromotionFailure=false, effectuez un GC complet à la place
- Si HandlePromotionFailure=true, il continuera à vérifier si l'espace continu maximum disponible dans l'ancienne génération est supérieur à la taille moyenne des objets promus à l'ancienne génération
- Le paramètre HandlePromotionFailure n'est pas valide après JDK7. Tant que l'espace continu de l'ancienne génération est supérieur à la taille totale des objets de nouvelle génération ou supérieur à la taille moyenne des objets promus à l'ancienne génération, MonitorGC sera exécuté, sinon FullGC
Algorithme de récupération de place de l'ancienne génération
Algorithme de classement de balisage
L'algorithme de collecte de copie nécessite plus d'opérations de copie lorsque le taux de survie des objets est élevé, et l'efficacité diminue. Plus important encore, si vous ne voulez pas gaspiller 50 % de l'espace mémoire, vous devez fournir de l'espace supplémentaire pour les garanties d'allocation. Étant donné que le taux de survie des objets de l'ancienne génération est relativement élevé et qu'aucune autre mémoire ne peut être trouvée pour la garantie d'allocation , l'ancienne génération ne peut généralement pas utiliser directement cet algorithme de collecte.
Selon les caractéristiques de l'ancienne génération, quelqu'un a amélioré le "mark-clear" et a proposé l'algorithme "mark-sort". Le processus de marquage de l'algorithme "mark-sort" est le même que celui de l'algorithme "mark-clear", mais les étapes suivantes ne nettoient pas directement les objets recyclables, mais laissent tous les objets survivants se déplacer vers une extrémité, puis directement nettoyer les objets à l'extérieur de la limite de fin .
moment du déclenchement
- Lors de l'appel de System.gc, le système suggère d'exécuter Full GC, mais pas nécessairement
- Espace insuffisant dans l'ancienne génération
- La garantie d'allocation d'espace a échoué
- JDK 1.7 et l'espace de la génération permanente précédente (zone de méthode) est insuffisant
- Après Minor GC, la taille moyenne de l'ancienne génération est supérieure à la mémoire disponible de l'ancienne génération
- Lorsque CMS GC gère les ordures flottantes, si l'espace de nouvelle génération est insuffisant, le mécanisme de garantie d'allocation d'espace sera adopté, et si l'espace d'ancienne génération est insuffisant, Full GC sera déclenché
Apportez un Young GC lorsque l'Old GC est exécuté
- Conditions de déclenchement OldGC
- Vérifiez avant que le Young GC ne se produise. Si "l'espace mémoire continu disponible dans l'ancienne génération" < "la taille moyenne du nombre total d'objets promus à l'ancienne génération après le Young GC dans la nouvelle génération", cela signifie que les objets peuvent être promu à l'ancienne génération après ce Young GC La taille peut dépasser l'espace mémoire actuellement disponible de l'ancienne génération. À ce moment, un Old GC doit être déclenché pour libérer de l'espace pour l'ancienne génération, puis exécuter le Young GC
- Après l'exécution de Young GC, un lot d'objets doit être mis dans l'ancienne génération. A ce moment, l'ancienne génération n'a pas assez d'espace mémoire pour stocker ces objets. A ce moment, un Old GC doit être déclenché immédiatement ( l'espace restant de l'ancienne génération est supérieur à la moyenne de la jeune génération précédente entrant dans l'ancienne taille, mais les objets entrant dans la vieillesse après ce recyclage sont bien plus grands que la taille moyenne précédente)
- Si le taux d'utilisation de la mémoire de l'ancienne génération dépasse 92 %, l'ancien GC doit être déclenché directement. Bien entendu, ce ratio peut être ajusté via des paramètres.
Pour le dire simplement, il n'y a pas assez d'espace dans l'ancienne génération, et plus aucun objet ne peut être placé.À ce moment, il est nécessaire d'exécuter Old GC pour collecter les ordures dans l'ancienne génération.
- expliquer
- Si l'ancien GC est causé par la condition 1, cela signifie qu'il n'y a pas suffisamment d'espace dans l'ancienne génération et que le jeune GC ne peut pas être exécuté. Il est nécessaire d'effectuer d'abord l'ancien GC, puis le jeune GC, afin que l'ancien GC se produise avant le Yonug GC
- S'il est causé par la condition 2, il n'y a pas suffisamment d'espace après Young GC, ce qui à son tour déclenche Old GC
- Dans de nombreux mécanismes de mise en œuvre de JVM, en fait, lorsque les conditions ci-dessus sont remplies, cela déclenche en fait un GC complet.Ce GC complet comprendra le GC jeune, l'ancien GC et le GC de génération permanente.