Maison >Java >javaDidacticiel >Une brève discussion sur l'allocation de mémoire Java et les stratégies de recyclage

Une brève discussion sur l'allocation de mémoire Java et les stratégies de recyclage

巴扎黑
巴扎黑original
2017-06-26 10:41:411148parcourir

1. Introduction

La gestion automatique de la mémoire mentionnée dans le système technologique Java concerne finalement deux problèmes : l'allocation de mémoire et le recyclage. Je vous ai déjà parlé des connaissances pertinentes sur le recyclage Java, et j'en parlerai. à vous aujourd'hui. Parlons de l'allocation des objets Java en mémoire. En termes simples, l'allocation mémoire des objets est une allocation sur le tas. Les objets sont principalement alloués sur Eden de nouvelle génération (la génération des objets en mémoire sera complétée lors du garbage collection. Si vous souhaitez en savoir plus, vous pouvez également vous référer "Compréhension approfondie de la machine virtuelle Java"), si le tampon d'allocation de thread local est démarré, il sera alloué sur le TLAB en fonction de la priorité du thread. Dans quelques cas, il est également attribué directement à l'ancienne génération.

2. Stratégie d'allocation classique

1. Les objets sont alloués en premier sur Eden

Dans des circonstances normales, les objets sont alloués en premier sur Eden. Lors de l'allocation, la JVM lancera un GC mineur. S'il n'y a toujours pas assez d'espace alloué, il existe d'autres mesures, qui seront mentionnées ci-dessous.

Définissez le paramètre de journal impair de la machine virtuelle -XX:+PrintGCDetails Pendant le garbage collection, le journal de recyclage de la mémoire sera imprimé et, à la fin du processus, l'allocation actuelle de chaque zone de mémoire sera affichée. Regardons un exemple spécifique. Tout d'abord, vous devez définir les paramètres jvm -Xms20m -Xmx20m -Xmn10m. Ces trois paramètres indiquent que la taille du tas Java est de 20 M et que 10 M sont alloués à la nouvelle génération et les 10 M restants. est attribué à l’ancienne génération. -XX:SurvivorRatio=8 est le ratio par défaut d'Eden et Survivor dans la nouvelle génération de jvm. La valeur par défaut est 8:1. La raison en est que 98 % des objets de la nouvelle génération seront recyclés dans le prochain GC, il est donc très approprié d'utiliser l'algorithme de copie pour le garbage collection. Par conséquent, sur les 10 M de mémoire de la nouvelle génération, 8 M sont Eden, 1M est Survivor, et l'autre 1M est inutilisé. Le bloc mémoire qui coopère avec l'algorithme de copie est également un Survivant.

 1 public class ReflectTest { 2  3     private static final int _1MB = 1024*1024; 4      5     public static void testAllocation(){ 6         byte[] allocation1 , allocation2 , allocation3 , allocation4; 7         allocation1 = new byte[2 * _1MB]; 8         allocation2 = new byte[2 * _1MB]; 9         allocation3 = new byte[2 * _1MB];10         allocation4 = new byte[6 * _1MB];11     }12     13     public static void main(String[] args) {14         ReflectTest.testAllocation();15     }16     17 }

Le résultat est le suivant

Heap
 PSYoungGen      total 9216K, used 6651K [0x000000000b520000, 0x000000000bf20000, 0x000000000bf20000)
  eden space 8192K, 81% used [0x000000000b520000,0x000000000bb9ef28,0x000000000bd20000)
  from space 1024K, 0% used [0x000000000be20000,0x000000000be20000,0x000000000bf20000)
  to   space 1024K, 0% used [0x000000000bd20000,0x000000000bd20000,0x000000000be20000)
 PSOldGen        total 10240K, used 6144K [0x000000000ab20000, 0x000000000b520000, 0x000000000b520000)
  object space 10240K, 60% used [0x000000000ab20000,0x000000000b120018,0x000000000b520000)
 PSPermGen       total 21248K, used 2973K [0x0000000005720000, 0x0000000006be0000, 0x000000000ab20000)
  object space 21248K, 13% used [0x0000000005720000,0x0000000005a07498,0x0000000006be0000)

Vous pouvez voir qu'eden occupe 81%, indiquant que allocation1, allocation2, et allocation3 sont tous alloués sur l'Eden nouvelle génération.

2. Les objets volumineux sont directement alloués dans l'ancienne génération

Les objets volumineux font référence à des objets qui nécessitent une grande quantité d'espace mémoire continu pour être stockés, semblables aux chaînes et aux tableaux très longs. Les objets volumineux ne sont pas une bonne chose pour la distribution de la mémoire de la machine virtuelle. Lorsqu'on rencontre de nombreux objets volumineux qui ne survivent qu'un seul tour, il est plus difficile pour la JVM de gérer de tels problèmes lors de l'écriture du code. Le paramètre -XX:PretenureSizeThreshold est fourni dans la machine virtuelle. Les objets de taille supérieure à cette valeur sont directement alloués à l'ancienne génération. Le but est d'éviter une grande quantité de copie de mémoire entre la zone Eden et la zone Survivor. mentionné précédemment L'algorithme de recyclage et l'algorithme de copie ont déjà été mentionnés, je n'entrerai donc pas dans les détails.

public class ReflectTestBig {private static final int _1MB = 1024*1024;    public static void testAllocation(){byte[] allocation2 , allocation3 , allocation4;allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        allocation4 = new byte[6 * _1MB];
    }    public static void main(String[] args) {
        ReflectTestBig.testAllocation();
    }
    
}

Le résultat est le suivant

Heap
 PSYoungGen      total 8960K, used 4597K [0x000000000b510000, 0x000000000bf10000, 0x000000000bf10000)
  eden space 7680K, 59% used [0x000000000b510000,0x000000000b98d458,0x000000000bc90000)
  from space 1280K, 0% used [0x000000000bdd0000,0x000000000bdd0000,0x000000000bf10000)
  to   space 1280K, 0% used [0x000000000bc90000,0x000000000bc90000,0x000000000bdd0000)
 PSOldGen        total 10240K, used 6144K [0x000000000ab10000, 0x000000000b510000, 0x000000000b510000)
  object space 10240K, 60% used [0x000000000ab10000,0x000000000b110018,0x000000000b510000)
 PSPermGen       total 21248K, used 2973K [0x0000000005710000, 0x0000000006bd0000, 0x000000000ab10000)
  object space 21248K, 13% used [0x0000000005710000,0x00000000059f7460,0x0000000006bd0000)

Vous pouvez voir que l'allocation4 a dépassé l'ensemble -XX:PretenureSizeThreshold=3145728 , n'hésitez pas à l'attribuer4 Il est directement attribué à l'ancienne génération, et le taux d'occupation de l'ancienne génération est de 60 %. Notez que le paramètre -XX:PretenureSizeThreshold=3145728 ne peut pas être écrit sous la forme -XX:PretenureSizeThreshold=3m, sinon le JVM ne le reconnaîtra pas.

3. Les objets survivants à long terme entreront dans l'ancienne génération

Puisque la machine virtuelle adopte l'idée de la collecte par bandes pour gérer la mémoire, le recyclage de la mémoire doit identifier dans quels objets doivent être placés la nouvelle génération. Quels objets doivent être placés dans l’ancienne génération. Afin d'atteindre cet objectif, jvm définit un compteur d'âge (Age) pour chaque objet. Si l'objet est né en Eden et survit au premier GC mineur, et peut être stocké dans le Survivant, il sera déplacé vers le Survivant et l'âge de l'objet sera fixé à 1. Chaque fois qu'un objet échappe au GC Mineur, son âge sera augmenté de 1. Lorsque son âge dépassera le seuil d'un an, l'objet sera promu à l'ancienne génération. Ce seuil jvm est par défaut de 15 et peut être défini par -XX:MaxTenuringThreshold.

   m = 1024 * 1024  [] a1 =  [1 * m / 4[] a2 =  [7 *[] a3 =  [3 * m];

Le résultat est le suivant

[GC [DefNew: 7767K->403K(9216K), 0.0062209 secs] 7767K->7571K(19456K), 0.0062482 secs]   
[Times: user=0.00 sys=0.00, real=0.01 secs]   
a3 ok  
Heap  
 def new generation   total 9216K, used 3639K [0x331d0000, 0x33bd0000, 0x33bd0000)  
  eden space 8192K,  39% used [0x331d0000, 0x334f9040, 0x339d0000)  
  from space 1024K,  39% used [0x33ad0000, 0x33b34de8, 0x33bd0000)  
  to   space 1024K,   0% used [0x339d0000, 0x339d0000, 0x33ad0000)  
 tenured generation   total 10240K, used 7168K [0x33bd0000, 0x345d0000, 0x345d0000)  
   the space 10240K,  70% used [0x33bd0000, 0x342d0010, 0x342d0200, 0x345d0000)  
 compacting perm gen  total 12288K, used 381K [0x345d0000, 0x351d0000, 0x385d0000)  
   the space 12288K,   3% used [0x345d0000, 0x3462f548, 0x3462f600, 0x351d0000)  
    ro space 10240K,  55% used [0x385d0000, 0x38b51140, 0x38b51200, 0x38fd0000)  
    rw space 12288K,  55% used [0x38fd0000, 0x396744c8, 0x39674600, 0x39bd0000)

Vous pouvez voir que a2 a survécu une fois et que son âge est 1, ce qui satisfait l'ensemble -XX:MaxTenuringThreshold=1, donc a2 est entré dans l'ancienne génération et a3 est entré dans la nouvelle génération.

4. Détermination dynamique de l'âge de l'objet

Afin de mieux s'adapter à l'état de la mémoire des différents programmes, la machine virtuelle n'exige pas toujours que l'âge de l'objet atteigne la valeur définie par -XX:MaxTenuringThreshold Afin d'être promus à la vieillesse, si la somme des tailles de tous les objets de même âge dans l'espace Survivant est supérieure à la moitié de l'espace Survivant, les objets dont l'âge est supérieur ou égal à celui-ci age peut entrer directement dans la vieillesse sans atteindre la valeur définie dans -XX:MaxTenuringThreshold.

5. Garantie d'allocation d'espace

Lorsque un GC mineur se produit, la machine virtuelle détectera si la taille moyenne de chaque promotion vers l'ancienne génération est supérieure à l'espace restant de l'ancienne génération si. c'est plus grand, procéder directement One FUll GC. S'il est inférieur à, vérifiez si le paramètre HandlerPromotionFailyre autorise l'échec de la garantie. S'il est autorisé, seul le GC mineur sera effectué. S'il n'est pas autorisé, un GC FUll sera également amélioré. C'est-à-dire que lorsque la nouvelle génération Eden ne peut pas stocker l'objet modifié, l'objet sera stocké dans l'ancienne génération.

3. Paramètres des paramètres JVM couramment utilisés

1. -Xms : taille initiale du tas, par défaut (le paramètre MinHeapFreeRatio peut être ajusté) Lorsque la mémoire du tas libre est inférieure à 40 %, la JVM le fera. augmentez le tas jusqu'à -Limite maximale de Xmx.

2.

3. -Xmn : Taille de la jeune génération (1,4 ou lator), la taille ici est (eden + 2 espace survivant) Elle est différente de la nouvelle génération affichée dans jmap -heap.
La taille entière du tas = taille de la jeune génération + taille de l'ancienne génération + taille de la génération persistante.
Après avoir augmenté la jeune génération, la taille de l'ancienne génération sera réduite. Cette valeur a un plus grand impact sur les performances du système. Sun recommande officiellement une configuration de 3/8 de l'ensemble du tas.

4. -XX:NewSize : Définissez la taille de la jeune génération (pour 1,3/1,4).

5. -XX:MaxNewSize : La valeur maximale de la jeune génération (pour 1,3/1,4).

6. -XX:PermSize : Définit la valeur initiale de la génération persistante (perm gen).

7. -XX:MaxPermSize : Définissez la taille maximale de la génération persistante.

8. -Xss : La taille de la pile de chaque thread. Après JDK5.0, la taille de la pile de chaque thread était de 1 Mo. Dans le passé, la taille de la pile de chaque thread était de 256 Ko. le thread d'application peut être ajusté.. Sous la même mémoire physique, réduire cette valeur peut générer plus de threads. Cependant, le système d'exploitation a toujours des limites sur le nombre de threads dans un processus et ne peut pas être généré à l'infini. ~5000.

9. -XX:NewRatio : Le ratio de la jeune génération (y compris Eden et deux zones Survivor) à l'ancienne génération (à l'exclusion de la génération persistante), -XX:NewRatio=4 signifie la différence entre les jeunes. génération et ancienne génération La valeur du ratio est de 1:4 et la jeune génération représente 1/5 de la pile entière. Lorsque Xms=Xmx et Xmn sont définis, ce paramètre n'a pas besoin d'être défini.

10. -XX:SurvivorRatio : Le rapport de taille de la zone Eden et de la zone Survivant est fixé à 8, puis le rapport de deux zones Survivant pour une zone Eden est de 2:8, et une zone Survivant représente pour toute la jeune génération.

11. -XX:LargePageSizeInBytes : La taille de la page mémoire ne peut pas être trop grande, ce qui affectera la taille de Perm.

12. -XX:+DisableExplicitGC : Close System.gc()

13. -XX:MaxTenuringThreshold : L'âge maximum des déchets. passer par la zone Survivor, entrer directement dans l'ancienne génération. Pour les applications avec un grand nombre d'anciennes générations, l'efficacité peut être améliorée si cette valeur est définie sur une valeur plus grande, les objets de la jeune génération seront copiés plusieurs fois dans la zone Survivor, afin que plus d'objets puissent être ajoutés. Le temps de survie de la jeune génération augmente la probabilité d'être recyclé dans la jeune génération. Ce paramètre n'est efficace qu'en série GC.

14. -XX:PretenureSizeThreshold : Si l'objet dépasse la taille, il est alloué directement dans l'ancienne génération. L'octet d'unité n'est pas valide lorsque la nouvelle génération utilise Parallel Scavenge GC. Une autre situation où il est alloué directement. dans l'ancienne génération, il s'agit d'un grand objet tableau et il n'y a aucun objet de référence externe dans le tableau.

15. -XX:TLABWasteTargetPercent : Le pourcentage de TLAB dans la zone eden.

4. Supplément

La différence entre Minor GC et FUll GC :

Nouvelle génération GC (Minor GC) : fait référence à l'action de garbage collection qui se produit dans la nouvelle génération. , car les objets Java Les grands logarithmes ne peuvent pas échapper au premier tour de GC, donc le GC mineur est fréquemment utilisé et la vitesse de récupération est généralement plus rapide.

GC ancienne génération (FULL GC/Major GC) : désigne les GC qui surviennent dans l'ancienne génération. Lorsque les Major GC apparaissent, ils sont souvent accompagnés d'au moins un Minor GC (mais pas absolument, dans la). stratégie de collecte du collecteur ParallelScavenge) Il existe un processus de sélection directe pour le Major GC). La vitesse du Major GC est généralement plus de 10 fois plus lente que celle du Minor 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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn