Maison > Java > javaDidacticiel > le corps du texte

Tester l'impact du garbage collector GC sur le débit en Java

高洛峰
Libérer: 2017-01-17 15:48:26
original
1717 Les gens l'ont consulté

J'ai découvert par hasard la définition de "Cochon dans le Python (Remarque : c'est un peu comme le serpent gourmand et insuffisant avalant l'éléphant)" en chinois en regardant le glossaire de gestion de la mémoire, j'ai donc trouvé cet article . En apparence, ce terme fait référence au GC qui fait constamment la promotion de gros objets d’une génération à l’autre. C'est comme si un python avalait sa proie en entier, de sorte qu'elle ne pouvait pas bouger pendant qu'elle digère.

Pendant les 24 heures suivantes, mon esprit était rempli d'images de ce python suffocant dont je ne parvenais pas à me débarrasser. Comme le disent les psychiatres, la meilleure façon de soulager la peur est d’en parler. D'où cet article. Mais la prochaine histoire dont nous voulons parler n'est pas celle de Python, mais du réglage GC. Je le jure devant Dieu.

Tout le monde sait que les pauses du GC peuvent facilement provoquer des goulots d'étranglement dans les performances. Les JVM modernes sont livrées avec des garbage collectors avancés lors de leur sortie, mais d'après mon expérience, il est extrêmement difficile de trouver la configuration optimale pour une application donnée. Le réglage manuel a peut-être encore une lueur d'espoir, mais vous devez comprendre les mécanismes exacts de l'algorithme GC. À cet égard, cet article vous sera utile. Ci-dessous, j'utiliserai un exemple pour expliquer comment un petit changement dans la configuration de la JVM affecte le débit de votre application.

Exemple

L'application que nous utilisons pour démontrer l'impact du GC sur le débit n'est qu'un simple programme. Il contient deux fils :

PigEater – Il imitera le processus d'un python géant mangeant un gros cochon gras. Le code fait cela en ajoutant 32 Mo d'octets à java.util.List et en dormant 100 ms après chaque hirondelle.
PigDigester – Il simule le processus de digestion asynchrone. Le code qui implémente la digestion définit simplement la liste des porcs comme vide. Puisqu'il s'agit d'un processus fatiguant, ce thread sera mis en veille pendant 2 000 ms à chaque fois après avoir effacé la référence.
Les deux threads fonctionneront dans une boucle while, mangeant et digérant jusqu'à ce que le serpent soit plein. Cela nécessiterait de manger environ 5 000 porcs.

package eu.plumbr.demo;
public class PigInThePython {
  static volatile List pigs = new ArrayList();
  static volatile int pigsEaten = 0;
  static final int ENOUGH_PIGS = 5000;
  public static void main(String[] args) throws InterruptedException {
    new PigEater().start();
    new PigDigester().start();
  }
  static class PigEater extends Thread {
    @Override
    public void run() {
      while (true) {
        pigs.add(new byte[32 * 1024 * 1024]); //32MB per pig
        if (pigsEaten > ENOUGH_PIGS) return;
        takeANap(100);
      }
    }
  }
  static class PigDigester extends Thread {
    @Override
    public void run() {
      long start = System.currentTimeMillis();
      while (true) {
        takeANap(2000);
        pigsEaten+=pigs.size();
        pigs = new ArrayList();
        if (pigsEaten > ENOUGH_PIGS)  {
          System.out.format("Digested %d pigs in %d ms.%n",pigsEaten, System.currentTimeMillis()-start);
          return;
        }
      }
    }
  }
  static void takeANap(int ms) {
    try {
      Thread.sleep(ms);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Copier après la connexion

Nous définissons désormais le débit de ce système comme « le nombre de porcs pouvant être digérés par seconde ». En considérant qu'un cochon est introduit dans ce python toutes les 100 ms, nous pouvons voir que le débit maximum théorique de ce système peut atteindre 10 cochons/seconde.

Exemple de configuration GC

Jetons un coup d'œil aux performances de l'utilisation de deux systèmes de configuration différents. Quelle que soit la configuration, l'application fonctionne sur un Mac double cœur avec 8 Go de RAM (OS X10.9.3).

La première configuration :

Heap 1,4G (-Xms4g -Xmx4g)
2. Utilisez CMS pour nettoyer l'ancienne génération (-XX : UseConcMarkSweepGC) et utilisez le collecteur parallèle pour nettoyer la nouvelle génération Generation (-XX : UseParNewGC)
3. Allouez 12,5% du tas (-Xmn512m) à la nouvelle génération et limitez les tailles de la zone Eden et de la zone Survivor pour qu'elles soient identiques. .
La deuxième configuration est légèrement différente :

Tas 1,2G (-Xms2g -Xms2g)
2 La nouvelle génération et l'ancienne génération utilisent Parellel GC (-XX : UseParallelGC)
. 3. Allouez 75 % du tas à la nouvelle génération (-Xmn 1536m)
4. Il est maintenant temps de parier sur quelle configuration fonctionnera le mieux (c'est-à-dire combien de porcs peuvent être mangés par seconde, rappelez-vous Bar. ) ? Ceux qui ont mis leurs jetons sur la première configuration, vous serez déçus. Les résultats sont tout le contraire :

1. La première configuration (grand tas, grande ancienne génération, CMS GC) peut manger 8,2 porcs par seconde
2. La deuxième configuration (petit tas, grand Le nouveau génération, Parellel GC) peut manger 9,2 porcs par seconde

Regardons maintenant ce résultat objectivement. Les ressources allouées sont 2 fois moindres mais le débit est augmenté de 12%. Cela est contraire au bon sens et il est donc nécessaire d’analyser plus en profondeur ce qui se passe.

Analyser les résultats du GC

La raison n'est en fait pas compliquée. Il vous suffit d'examiner attentivement ce que fait le GC lors de l'exécution du test pour trouver la réponse. C'est ici que vous choisissez l'outil que vous souhaitez utiliser. Avec l'aide de jstat, j'ai découvert le secret qui se cache derrière. La commande est probablement la suivante :

jstat -gc -t -h20 PID 1s
Copier après la connexion

En analysant les données, j'ai remarqué que la configuration 1 a connu 1129 cycles GC (YGCT_FGCT) et a dépensé un total de 63,723 secondes :

Timestamp        S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
594.0 174720.0 174720.0 163844.1  0.0   174848.0 131074.1 3670016.0  2621693.5  21248.0 2580.9   1006   63.182  116 0.236   63.419
595.0 174720.0 174720.0 163842.1  0.0   174848.0 65538.0  3670016.0  3047677.9  21248.0 2580.9   1008   63.310  117 0.236   63.546
596.1 174720.0 174720.0 98308.0 163842.1 174848.0 163844.2 3670016.0   491772.9  21248.0 2580.9   1010   63.354  118 0.240   63.595
597.0 174720.0 174720.0  0.0   163840.1 174848.0 131074.1 3670016.0   688380.1  21248.0 2580.9   1011   63.482  118 0.240   63.723
Copier après la connexion

La deuxième configuration a fait une pause au total 168 fois (YGCT FGCT) et n'a pris que 11,409 secondes.

Timestamp        S0C    S1C    S0U    S1U      EC       EU        OC         OU       PC     PU    YGC     YGCT    FGC    FGCT     GCT
539.3 164352.0 164352.0  0.0    0.0   1211904.0 98306.0   524288.0   164352.2  21504.0 2579.2 27    2.969  141 8.441   11.409
540.3 164352.0 164352.0  0.0    0.0   1211904.0 425986.2  524288.0   164352.2  21504.0 2579.2 27    2.969  141 8.441   11.409
541.4 164352.0 164352.0  0.0    0.0   1211904.0 720900.4  524288.0   164352.2  21504.0 2579.2 27    2.969  141 8.441   11.409
542.3 164352.0 164352.0  0.0 0.0   1211904.0 1015812.6  524288.0   164352.2  21504.0 2579.2 27 2.969  141 8.441   11.409
Copier après la connexion

Considérant que la charge de travail dans les deux cas est égale, donc - dans cette expérience de consommation de porcs, lorsque le GC ne trouve pas d'objets à longue durée de vie, il peut nettoyer les déchets plus rapidement. Avec la première configuration, la fréquence de fonctionnement du GC sera d'environ 6 à 7 fois et le temps de pause total sera de 5 à 6 fois.

Raconter cette histoire a deux objectifs. Avant tout, je voulais sortir de mon esprit ce python convulsif. Un autre avantage plus évident est que le réglage GC est une expérience très habile et nécessite que vous ayez une compréhension approfondie des concepts sous-jacents. Bien que celle utilisée dans cet article ne soit qu’une application très courante, les différents résultats de la sélection auront également un impact important sur votre planification de débit et de capacité. Dans les applications réelles, la différence sera encore plus grande. C'est donc à vous de décider si vous pouvez maîtriser ces concepts, ou simplement vous concentrer sur votre travail quotidien et laisser Plumbr déterminer la configuration GC la plus adaptée à vos besoins.

Pour plus d'articles liés au test de l'impact du garbage collector GC sur le débit en Java, veuillez faire attention au site Web PHP chinois !

source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal