Maison >Java >javaDidacticiel >Analyse de la stratégie d'allocation et de recyclage de la mémoire Java

Analyse de la stratégie d'allocation et de recyclage de la mémoire Java

怪我咯
怪我咯original
2017-07-02 10:35:351337parcourir

L'éditeur suivant vous apportera une compréhension approfondie des stratégies d'allocation de mémoire et de recyclage Java. L'éditeur le trouve plutôt bon, je vais donc le partager avec vous maintenant et le donner comme référence pour tout le monde. Suivons l'éditeur et jetons un coup d'œil.

1. Introduction

La gestion automatique de la mémoire mentionnée dans le système technologique Java concerne en fin de compte la mémoire. . Concernant les deux problématiques d'allocation et de recyclage, je vous ai déjà parlé du recyclage Java. Aujourd'hui, je vais vous parler 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 <.>

Généralement, les objets sont d'abord alloués sur Eden. Lorsqu'Eden n'a pas assez d'espace pour l'allocation, 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 lorsque le processus

se terminera , les zones de mémoire actuelles seront affichées. . situation de distribution. 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.

public class ReflectTest {

  private static final int _1MB = 1024*1024;
  
  public static void testAllocation(){
    byte[] allocation1 , allocation2 , allocation3 , allocation4;
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    allocation4 = new byte[6 * _1MB];
  }
  
  public static void main(String[] args) {
    ReflectTest.testAllocation();
  }
  
}
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 l'allocation1, l'allocation2 et l'allocation3 sont toutes allouées 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 aux objets qui nécessitent une grande quantité d'espace mémoire continu pour store, similaire au genre de

chaînes très longues et de tableaux. 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. L'allocation4 est directement allouée à l'ancienne génération, et l'allocation4 est directement allouée à l'ancienne génération. le taux d'occupation des anciennes générations 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 collecte de bandes pour gérer mémoire, la mémoire Recyclage doit identifier quels objets doivent être placés dans la nouvelle génération et 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.

public class JavaTest { 
 
  static int m = 1024 * 1024; 
 
  public static void main(String[] args) { 
    byte[] a1 = new byte[1 * m / 4]; 

     byte[] a2 = new byte[7 * m]; 

     byte[] a3 = new byte[3 * m]; //GC 
  } 
}
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, l'âge est 1 et répond à 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 des objets

Afin de mieux s'adapter à l'état de la mémoire des différents programmes, les machines virtuelles ne nécessitent pas toujours d'objets. L'âge doit atteindre la valeur fixée par -XX:MaxTenuringThreshold pour être promu à l'âge avancé. Si la somme des tailles de tous les objets du 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 à cet âge peut saisir directement l'âge de la vieillesse, il n'est pas nécessaire d'atteindre la valeur de réglage dans -XX:MaxTenuringThreshold.

5. Garantie d'attribution 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 elle est supérieure, un GC COMPLET sera effectué directement. 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 de tas initiale, tas libre par défaut (le paramètre MinHeapFreeRatio peut être ajusté). mémoire Lorsqu'il est inférieur à 40%, la JVM augmentera le tas jusqu'à la 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 y a un grand tableau Object, et il n'y a pas d'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 le GC mineur et le GC FUll :

GC de nouvelle génération (GC mineur) : fait référence à l'action de récupération de place qui se produit dans la nouvelle génération. Parce que la plupart des objets Java ne peuvent pas échapper au premier tour de GC, le GC mineur est fréquemment utilisé. la vitesse de recyclage est généralement plus rapide.

GC ancienne génération (FULL GC/Major GC) : fait référence au GC qui survient dans l'ancienne génération. Lorsque le Major GC apparaît, il est souvent accompagné d'au moins un Minor GC (. mais pas absolument, dans La stratégie de collecte du collecteur ParallelScavenge inclut le processus de sélection directe du 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