
Partage de donnĂ©es de classe d'application (AppCDS) - Fonction JVM pour accĂ©lĂ©rer le dĂ©marrage et Ă©conomiser de la mĂ©moire. AprĂšs ĂȘtre apparu Ă ses dĂ©buts dans HotSpot dans JDK 1.5 (2004), il est restĂ© longtemps trĂšs limitĂ©, et mĂȘme partiellement commercial. Ce n'est qu'avec OpenJDK 10 (2018) qu'il a Ă©tĂ© mis Ă la disposition de simples mortels, tout en Ă©largissant le champ d'application. Et rĂ©cemment, Java 13 a essayĂ© de simplifier cette application.
L'idĂ©e d'AppCDS est de «partager» des classes une fois chargĂ©es entre des instances de la mĂȘme machine virtuelle Java sur le mĂȘme hĂŽte. Il semble que cela devrait ĂȘtre idĂ©al pour les microservices, en particulier les "broilers" sur Spring Boot avec leurs milliers de classes de bibliothĂšque, car maintenant ces classes n'auront plus besoin d'ĂȘtre chargĂ©es (analysĂ©es et vĂ©rifiĂ©es) Ă chaque dĂ©marrage de chaque instance JVM, et elles ne seront pas dupliquĂ©es en mĂ©moire. Cela signifie que le lancement devrait devenir plus rapide et la consommation de mĂ©moire devrait ĂȘtre infĂ©rieure. Merveilleux, non?
Tout est ainsi, tout est ainsi. Mais si vous, l'odnokhabryanin, ne croyiez pas aux panneaux du boulevard, mais aux chiffres et aux exemples spécifiques, alors bienvenue à Kat - essayons de comprendre comment c'est vraiment ...
Au lieu de l'avertissement
Avant vous n'est pas un guide d'utilisation d'AppCDS, mais un rĂ©sumĂ© des rĂ©sultats d'une petite Ă©tude. J'Ă©tais intĂ©ressĂ© Ă comprendre comment cette fonction JVM est applicable dans mon projet de travail, et j'ai essayĂ© de l'Ă©valuer du point de vue d'un dĂ©veloppeur d'entreprise, en exposant le rĂ©sultat dans cet article. Cela n'incluait pas des sujets tels que l'utilisation d'AppCDS sur le chemin du module, l'implĂ©mentation d'AppCDS sur d'autres machines virtuelles (pas HotSpot) et les subtilitĂ©s de l'utilisation des conteneurs. Mais il y a une partie thĂ©orique pour explorer le sujet, ainsi qu'une partie expĂ©rimentale Ă©crite pour que vous puissiez rĂ©pĂ©ter l'expĂ©rience vous-mĂȘme. Aucun rĂ©sultat n'a encore Ă©tĂ© appliquĂ© en production, mais qui sait Ă quoi ressemblera demain ...
Théorie
Une brĂšve introduction Ă AppCDS
La connaissance de ce sujet peut avoir eu lieu dans plusieurs sources, par exemple:
- dans un article de Nikolai Parlog (y compris Java 13 buns, mais sans Spring Boot)
- dans un rapport et un article de Volker Simonis (sans Java 13, mais avec des détails)
- dans un rapport de l' auteur de ces lignes (sans Java 13, mais en mettant l'accent sur Spring Boot)
Afin de ne pas me lancer dans une nouvelle narration, je ne soulignerai que quelques points importants pour cet article.
Tout d'abord, AppCDS est une extension de la fonction CDS qui est apparue depuis longtemps dans HotSpot, dont l'essence est la suivante:

Pour donner vie aux deux idées, vous devez procéder comme suit (en termes généraux):
- Obtenez une liste des classes que vous souhaitez partager entre les instances d'application
- Fusionnez ces classes dans une archive adaptée au mappage de la mémoire
- Connectez l'archive à chaque instance de l'application au démarrage
Il semblerait que l'algorithme ne soit que 3 étapes - prenez-le et faites-le. Mais ici commence la nouvelle, toutes sortes de choses.
La mauvaise chose est que dans le pire des cas, chacun de ces Ă©lĂ©ments se transforme en au moins un lancement JVM avec ses propres options spĂ©cifiques, ce qui signifie que l'algorithme entier est un jonglage subtil du mĂȘme type d'options et de fichiers. Cela ne semble pas trĂšs prometteur, n'est-ce pas?
Mais il y a une bonne nouvelle: les travaux d'amélioration de cet algorithme sont en cours , et à chaque version de Java, son application devient plus simple. Ainsi, par exemple:
- Dans OpenJDK 10 et 11, vous pouvez ignorer l'étape 1 si vous souhaitez partager uniquement les classes JDK principales, car elles ont déjà été compilées pour nous et placées dans
$JAVA_HOME\lib\classlist
(â1200 pcs.). - Dans OpenJDK 12, vous pouvez ignorer l' Ă©tape 2 , car avec la liste des classes, l'archive de distribution comprend Ă©galement une archive prĂȘte Ă l'emploi avec eux, qui est utilisĂ©e prĂȘte Ă l'emploi et ne nĂ©cessite pas de connexion explicite.
- Au cas oĂč vous souhaiteriez partager tout le reste (et le souhaitez gĂ©nĂ©ralement)
OpenJDK 13 fournit des archives Dynamic CDS - des archives qui sont collectées pendant le fonctionnement de l'application et enregistrées lors de la dotation en personnel. Cela vous permet de réduire les points 1 et 2 en un point pas trop confus (bien que tout ne soit pas si simple, mais plus à ce sujet plus tard).
Ainsi, quel que soit le processus de préparation d'AppCDS, les 3 étapes énumérées ci-dessus sont toujours derriÚre, juste dans certains cas, elles sont voilées.
Comme vous l'avez probablement remarquĂ©, avec l'avĂšnement d'AppCDS, de nombreuses classes d'application commencent une double vie: elles vivent simultanĂ©ment dans leurs anciens emplacements (le plus souvent des fichiers JAR) et dans une nouvelle archive partagĂ©e. Dans le mĂȘme temps, le dĂ©veloppeur continue de les modifier / supprimer / complĂ©ter au mĂȘme endroit, et la JVM les reprend de la nouvelle lorsqu'elle fonctionne. Il n'est pas nĂ©cessaire d'ĂȘtre un devin pour voir le danger d'une telle situation: si rien n'est fait, tĂŽt ou tard des copies des cours se corrodent, et nous obtiendrons de nombreux charmes de «l'enfer JAR» typique. Il est clair que la JVM ne peut pas empĂȘcher les changements de classe, mais elle devrait ĂȘtre capable de dĂ©tecter un Ă©cart dans le temps. Cependant, faire cela en comparant les classes par paires, mĂȘme par des sommes de contrĂŽle, est une idĂ©e; il peut annuler le reste des gains de productivitĂ©. C'est probablement pourquoi les ingĂ©nieurs JVM n'ont pas sĂ©lectionnĂ© les classes individuelles comme objet de comparaison, mais tout le chemin de classe, et ont dĂ©clarĂ© dans la documentation AppCDS: "Le chemin de classe lors de la crĂ©ation d'une archive partagĂ©e doit ĂȘtre le mĂȘme (ou au moins un prĂ©fixe) que lors des lancements ultĂ©rieurs de l'application."
Notez que le chemin de classe utilisĂ© au moment de la crĂ©ation de l'archive doit ĂȘtre le mĂȘme que (ou un prĂ©fixe) le chemin de classe utilisĂ© au moment de l'exĂ©cution.
Mais ce n'est pas une dĂ©claration sans ambiguĂŻtĂ©, car, comme vous vous en souvenez, un chemin de classe peut ĂȘtre formĂ© de diffĂ©rentes maniĂšres, telles que:
- lire des fichiers
.class
nus à partir de répertoires de packages compilés,
par exemple java com.example.Main
- l'analyse des répertoires avec des fichiers JAR lors de l'utilisation de caractÚres génériques,
par exemple java -cp mydir/* com.example.Main
- liste explicite des fichiers JAR et / ou ZIP,
par exemple java -cp lib1.jar;lib2.jar com.example.Main
(sans parler du fait que le -cp/-classpath/--class-path
peut Ă©galement ĂȘtre dĂ©fini diffĂ©remment, par exemple via les options JVM -cp/-classpath/--class-path
, la CLASSPATH
environnement CLASSPATH
ou l'attribut du fichier JAR Class-Path
Ă lancer)
Parmi ces méthodes, une seule est prise en charge dans AppCDS - énumération explicite des fichiers JAR. Apparemment, les ingénieurs HotSpot JVM ont estimé que la comparaison des chemins de classe dans l'archive AppCDS et dans l'application lancée ne serait suffisamment rapide et fiable que s'ils étaient spécifiés aussi clairement que possible - avec une liste exhaustive habituelle.
CDS / AppCDS prend en charge l'archivage des classes Ă partir de fichiers JAR uniquement.
Il est important de noter ici que cette déclaration n'est pas récursive, c'est-à -dire ne s'applique pas aux fichiers JAR à l'intérieur des fichiers JAR (sauf s'il s'agit de Dynamic CDS, voir ci-dessous). Cela signifie que les poupées JAR habituelles émises par Spring Boot ne fonctionneront pas comme ça avec AppCDS normal, vous devrez vous asseoir.
Un autre inconvénient du travail de CDS est que les archives partagées sont projetées sur la mémoire avec des adresses fixes (commençant généralement à 0x800000000
). En soi, ce n'est pas mauvais, mais comme la randomisation de la disposition de l'espace d'adressage (ASLR) est activĂ©e par dĂ©faut sur la plupart des systĂšmes d'exploitation, la plage de mĂ©moire requise peut ĂȘtre partiellement occupĂ©e. Dans ce cas, la -Xshare
HotSpot fait lâ option spĂ©ciale -Xshare
qui prend en charge trois valeurs:
-Xshare:on
- force CDS / AppCDS; si la plage est occupée, la JVM se termine avec une erreur. Ce mode n'est pas recommandé pour une utilisation en production , car cela peut entraßner des plantages sporadiques lors du lancement des applications.-Xshare:off
- (vous) changez de CDS / AppCDS; désactive complÚtement l'utilisation des données partagées (y compris les archives intégrées)-Xshare:auto
- le comportement par défaut de la JVM lorsqu'elle, en cas d'impossibilité d'allouer la plage de mémoire requise, se rend discrÚtement et charge les classes comme d'habitude
Au moment de la rédaction de cet article, Oracle s'efforce simplement de résoudre ces problÚmes, mais aucun numéro de version n'a encore été attribué.
Ces options nous sont partiellement utiles plus tard, mais pour l'instant, regardons ...
Applications AppCDS
Il existe plusieurs façons d'utiliser AppCDS. ruine ta vie optimiser le travail des microservices. Leur complexité et leur profit potentiel varient considérablement. Il est donc important de décider immédiatement lequel sera discuté plus tard.
Le plus simple est de ne pas utiliser mĂȘme AppCDS, mais seulement CDS - c'est lorsque seules les classes de plate-forme entrent dans l'archive partagĂ©e (voir "Une brĂšve introduction Ă AppCDS"). Nous supprimerons cette option immĂ©diatement, car lorsqu'elle est appliquĂ©e aux microservices sur Spring Boot, elle donne trop peu de profit. Cela peut ĂȘtre vu par la proportion du nombre de classes partagĂ©es dans leur distribution gĂ©nĂ©rale en utilisant l'exemple d'un vrai microservice (voir le segment vert):

Plus complexe, mais prometteur est l'utilisation d'AppCDS Ă part entiĂšre, c'est-Ă -dire l'inclusion des classes de bibliothĂšque et d'application dans la mĂȘme archive. Il s'agit de toute une famille d'options dĂ©rivĂ©es de combinaisons du nombre d'applications participantes et du nombre d'instances. Voici les Ă©valuations subjectives de l'auteur sur les avantages et les difficultĂ©s de diverses applications d'AppCDS.
Faites attention:
- Dans l'application Ă une application dans une instance (n ° 1), le gain de mĂ©moire peut s'avĂ©rer nul ou mĂȘme nĂ©gatif (surtout lors de la mesure sous Windows )
- La création de l'archive partagée correcte nécessite des actions, dont la complexité ne dépend pas du nombre de copies que l'application sera ensuite lancée (comparer les paires d'options n ° 1-2 et n ° 3-4)
- Dans le mĂȘme temps, le passage d'une instance Ă plusieurs donne Ă©videmment une augmentation du bĂ©nĂ©fice pour les deux indicateurs, mais n'affecte pas la complexitĂ© de la prĂ©paration.
Dans cet article, nous n'atteindrons que l'option n ° 2 (à travers le n ° 1), car elle est assez simple pour une connaissance approfondie d'AppCDS et seulement pour elle sans astuces supplémentaires, nous pouvons utiliser les archives JEP-350 Dynamic CDS récemment publiées, que je veux ressentir en action.
Archives dynamiques du CDS
Les archives dynamiques CDS JEP-350 , l'une des principales innovations de Java 13, sont conçues pour simplifier l'utilisation d'AppCDS. Pour ressentir la simplification, vous devez d'abord comprendre la complexitĂ©. Permettez-moi de vous rappeler que l'algorithme d'application «propre» classique pour AppCDS se compose de 3 Ă©tapes: (1) obtenir une liste des classes partagĂ©es, (2) crĂ©er une archive Ă partir de celles-ci, et (3) exĂ©cuter l'application avec l'archive connectĂ©e. De ces Ă©tapes, seule la 3Ăšme est rĂ©ellement utile, le reste ne fait que la prĂ©parer. Et bien que l'obtention d'une liste de classes (Ă©tape # 1) puisse sembler trĂšs simple (dans certains cas, ce n'est mĂȘme pas nĂ©cessaire), en fait lorsque vous travaillez avec des applications non triviales, cela s'avĂšre ĂȘtre le plus difficile, en particulier en ce qui concerne Spring Boot. Le JEP-350 est donc nĂ©cessaire juste pour Ă©liminer cette Ă©tape, ou plutĂŽt l'automatiser. L'idĂ©e est que la JVM elle-mĂȘme dresse une liste des classes dont l'application a besoin, puis forme elle-mĂȘme l'archive dite «dynamique». D'accord, ça sonne bien. Mais le hic, c'est que maintenant il devient difficile de savoir Ă quel moment cesser d'accumuler des classes et procĂ©der Ă leur placement dans l'archive. Auparavant, dans l'AppCDS classique, nous avions choisi un tel moment nous-mĂȘmes et pouvions mĂȘme coincer entre ces actions pour changer quelque chose dans la liste des classes avant de le transformer en archive. Maintenant, cela se produit automatiquement et seulement Ă un moment, pour lequel les ingĂ©nieurs JVM ont peut-ĂȘtre choisi la seule option de compromis - l'arrĂȘt rĂ©gulier de la JVM. Cela signifie que l'archive ne sera pas créée avant l'arrĂȘt de l'application. Cette solution a deux consĂ©quences importantes:
- En cas de plantage de la JVM, l'archive ne sera pas créée, quelle que soit la beauté de la liste des classes accumulées d'ici là (vous ne pouvez pas l'extraire plus tard en utilisant des moyens réguliers).
- L'archive sera créée uniquement Ă partir des classes qui ont rĂ©ussi Ă se charger pendant la session d'application. Pour les applications Web, cela signifie que la crĂ©ation d'une archive en dĂ©marrant et en s'arrĂȘtant lĂ n'est pas correcte, car alors de nombreuses classes importantes n'entreront pas dans l'archive. Il est nĂ©cessaire d'exĂ©cuter au moins une requĂȘte HTTP sur l'application (et il est prĂ©fĂ©rable de l'exĂ©cuter correctement dans tous les scĂ©narios) afin que toutes les classes qu'elle utilise rĂ©ellement soient chargĂ©es.
Une diffĂ©rence importante entre les archives dynamiques et statiques est qu'elles constituent toujours un «module complĂ©mentaire» sur les archives statiques de base, qui peuvent ĂȘtre soit des archives intĂ©grĂ©es dans le kit de distribution Java, soit créées sĂ©parĂ©ment de maniĂšre classique en 3 Ă©tapes.
Syntaxiquement, l'utilisation des archives Dynamic CDS se résume à deux lancements JVM avec deux options:
- Essai avec l'option
-XX:ArchiveClassesAtExit=archive.jsa
, à la fin de laquelle une archive dynamique sera créée (vous pouvez spécifier n'importe quel chemin et nom) - Lancement utile avec l'option
-XX:SharedArchiveFile=archive.jsa
, qui utilisera l'archive précédemment créée
La deuxiÚme option n'est pas différente de la connexion d'une archive statique réguliÚre. Mais si tout à coup l'archive statique de base n'est pas à l'emplacement par défaut (à l'intérieur du JDK), cette option peut également inclure une indication du chemin d'accÚs, par exemple:
-XX:SharedArchiveFile=base.jsa:dynamic.jsa
(sous Windows, le sĂ©parateur de chemin doit ĂȘtre le caractĂšre ";")
Vous en savez maintenant assez sur AppCDS pour pouvoir le regarder en action.
Pratique
Lapin expérimental
Pour que notre application d'AppCDS dans la pratique ne se limite pas à un HelloWorld typique, nous prendrons comme base la vraie application sur Spring Boot. Mes collÚgues et moi devons souvent regarder les journaux des applications sur des serveurs de test distants et regarder en direct, tout comme ils sont écrits. Utiliser pour cela un agrégateur de journaux à part entiÚre (comme ELK) n'est souvent pas approprié; télécharger des fichiers journaux à l'infini - pendant longtemps, et regarder la sortie de la console grise de tail
est dĂ©primant. Par consĂ©quent, j'ai créé une application Web qui peut sortir tous les journaux en temps rĂ©el directement vers le navigateur, coloriser les lignes par niveau d'importance (en formatant XML en mĂȘme temps), agrĂ©ger plusieurs journaux en un seul, ainsi que d'autres astuces. Il s'appelle ANALOG (comme un «analyseur de journaux», bien que ce ne soit pas vrai) et se trouve sur GitHub . Cliquez sur la capture d'Ă©cran pour agrandir:

Techniquement, il s'agit d'une application sur Spring Boot + Spring Integration, sous le capot de laquelle tail
, docker
et kubectl
(pour prendre en charge les journaux de fichiers, les conteneurs Docker et les ressources Kubernetes, respectivement). Il se prĂ©sente sous la forme du fichier JAR Spring Boot «épais» classique. Au moment de l'exĂ©cution, classes10K classes sont suspendues dans la mĂ©moire de l'application, dont la grande majoritĂ© sont des classes Spring et JDK. Ăvidemment, ces classes changent assez rarement, ce qui signifie qu'elles peuvent ĂȘtre placĂ©es dans une archive partagĂ©e et rĂ©utilisĂ©es dans toutes les instances de l'application, Ă©conomisant de la mĂ©moire et du CPU.
Expérience unique
Appliquons maintenant les connaissances existantes de Dynamic AppCDS au lapin expérimental. Puisque tout est connu en comparaison, nous aurons besoin d'un point de référence - l'état du programme avec lequel nous comparerons les résultats obtenus pendant l'expérience.
Remarques introductives
- Toutes les autres commandes sont pour Linux. Les différences pour Windows et macOS ne sont pas fondamentales.
- La compilation JIT peut sensiblement affecter les rĂ©sultats et, en thĂ©orie, pour la puretĂ© de l'expĂ©rience, elle pourrait ĂȘtre dĂ©sactivĂ©e (avec l'option
-Xint
, comme cela a été fait dans l' article mentionné), mais dans un souci de plausibilité maximale, il a été décidé de ne pas le faire. - Les nombres suivants concernant l'heure de début ont été obtenus sur un serveur de test rapide. Sur les machines qui fonctionnent, des nombres similaires sont généralement plus modestes, mais comme nous ne nous intéressons pas aux valeurs absolues, mais aux incréments de pourcentage, nous considérons cette différence comme insignifiante.
- Afin de ne pas entrer prématurément dans la complexité de la mesure de la mémoire partagée, pour l'instant nous omettons d'obtenir des lectures précises en octets. Au lieu de cela, nous introduisons le concept de « potentiel CDS », exprimé en pourcentage du nombre de classes partagées par rapport au nombre total de classes chargées. Il s'agit bien sûr d'une quantité abstraite, mais d'un autre cÎté, elle affecte directement la consommation réelle de mémoire; de plus, sa définition ne dépend pas du tout de l'OS, et pour son calcul, seuls les logs sont suffisants.
Point de référence
Soit ce point l'état d'une application fraßchement téléchargée, c'est-à -dire sans utilisation explicite d'aucun AppCDS'ov et autres. Pour l'évaluer, nous avons besoin de:
Installez OpenJDK 13 (par exemple, la distribution Liberica domestique, mais pas la version lite).
Il doit Ă©galement ĂȘtre ajoutĂ© Ă la variable d'environnement PATH ou Ă JAVA_HOME
, par exemple, comme ceci:
export JAVA_HOME=~/tools/jdk-13
Téléchargez ANALOG (au moment de la rédaction, la derniÚre version était la v0.12.1).
Si nécessaire, vous pouvez spécifier dans le fichier config/application.yaml
du paramĂštre server.address
le nom d'hÎte externe pour accéder à l'application (par défaut, localhost
est spécifié).
Activez la journalisation du chargement de classe JVM.
Pour ce faire, vous pouvez JAVA_OPTS
la variable d'environnement JAVA_OPTS
avec cette valeur:
export JAVA_OPTS=-Xlog:class+load=info:file=log/class-load.log
Cette option sera transmise Ă la JVM et lui demandera de garantir la source de chaque classe.
Exécutez un test:
- Exécutez l'application avec le script
bin/analog
- Ouvrez http: // localhost: 8083 dans le navigateur, piquez les boutons et les daws
- ArrĂȘtez l'application en appuyant sur
Ctrl+C
dans la console de script bin/analog
Prendre le résultat (à partir des fichiers du log/
répertoire)
Nombre total de classes chargées (par class-load.log
):
cat class-load.log | wc -l 10463
Combien d'entre eux sont téléchargés à partir d'une archive partagée (selon elle):
grep -o 'source: shared' - class-load.log 1146
Heure de début moyenne (aprÚs une série de démarrages; par analog.log
):
grep -oE '\(JVM running for .+\)' analog.log | grep -oE '[0-9]\.[0-9]+' | awk '{ total += $1; count++ } END { print total/count }' 4.5225
Ainsi, à cette étape, le potentiel du CDS était de 1146/10463=0,1095
-11% . Si vous ĂȘtes surpris de l'origine des classes partagĂ©es (aprĂšs tout, nous n'avons pas encore inclus d'AppCDS), je vous rappelle qu'Ă partir de la 12Ăšme version, le JDK inclut l' archive CDS finie $JAVA_HOME/lib/server/classes.jsa
, construite par pas moins de liste de classes prĂȘte:
cat $JAVA_HOME/lib/classlist | wc -l 1170
Maintenant, aprÚs avoir évalué l'état initial de l'application, nous pouvons lui appliquer AppCDS et, par comparaison, comprendre ce que cela donne.
Expérience de base
Comme la documentation nous a été léguée, pour créer une archive AppCDS dynamique, vous devez effectuer un seul essai de l'application avec l'option -XX:ArchiveClassesAtExit
. DĂšs le prochain lancement, l'archive peut ĂȘtre utilisĂ©e et recevoir des bĂ©nĂ©fices. Pour vĂ©rifier cela sur le mĂȘme lapin expĂ©rimental (AnaLog), vous avez besoin de:
Ajoutez l'option spécifiée à la commande d'exécution:
export JAVA_OPTS="$JAVA_OPTS -XX:ArchiveClassesAtExit=work/classes.jsa"
Ătendre la journalisation:
export JAVA_OPTS="$JAVA_OPTS -Xlog:cds=debug:file=log/cds.log"
Cette option forcera le processus de construction d'une archive CDS Ă ĂȘtre enregistrĂ© lorsque l'application sera arrĂȘtĂ©e.
Effectuez le mĂȘme test que pour le point de rĂ©fĂ©rence:
- Exécutez l'application avec le script
bin/analog
- Ouvrez http: // localhost: 8083 dans le navigateur, piquez les boutons et les daws
- ArrĂȘtez l'application en appuyant sur
Ctrl+C
dans la console de script bin/analog
AprÚs cela, un énorme footcloth avec toutes sortes d'avertissements devrait tomber dans la console, et le log/cds.log
devrait ĂȘtre rempli de dĂ©tails; ils ne nous intĂ©ressent pas encore.
Faites passer le mode de lancement d'essai Ă utile:
export JAVA_OPTS="-XX:SharedArchiveFile=work/classes.jsa -Xlog:class+load=info:file=log/class-load.log -Xlog:class+path=debug:file=log/class-path.log"
Ici, nous ne JAVA_OPTS
pas la variable JAVA_OPTS
, mais nous la JAVA_OPTS
par de nouvelles valeurs qui incluent (1) l'utilisation d'une archive partagée, (2) la journalisation des sources de classe et (3) la journalisation des vérifications de chemin de classe.
Effectuez un lancement utile de l'application selon le schéma du paragraphe 3.
Prendre le résultat (à partir des fichiers du log/
répertoire)
Vérification de l'application réelle d'AppCDS (par le class-path.log
):
[0.011s][info][class,path] type=BOOT [0.011s][info][class,path] Expecting BOOT path=/home/upc/tools/jdk-13/lib/modules [0.011s][info][class,path] ok [0.011s][info][class,path] type=APP [0.011s][info][class,path] Expecting -Djava.class.path=/home/upc/tmp/analog/lib/analog.jar [0.011s][info][class,path] ok
Les marques ok
aprĂšs les lignes type=BOOT
et type=APP
indiquent respectivement l'ouverture, la vérification et le chargement réussis des archives CDS intégrées et appliquées.
Nombre total de classes chargées (par class-load.log
):
cat class-load.log | wc -l 10403
Combien d'entre eux sont téléchargés à partir d'une archive partagée (selon elle):
grep -o 'source: shared' -c class-load.log 6910
Heure de début moyenne (aprÚs une série de démarrages; par fichier analog.log
):
grep -oE '\(JVM running for .+\)' analog.log | grep -oE '[0-9]\.[0-9]+' | awk '{ total += $1; count++ } END { print total/count }' 4.04167
Mais Ă ce 6910/10403â0,66
, le potentiel du CDS Ă©tait dĂ©jĂ de 6910/10403â0,66
= 66% , c'est-Ă -dire qu'il a augmentĂ© de 55% par rapport au point de rĂ©fĂ©rence. Dans le mĂȘme temps, le temps de lancement moyen a Ă©tĂ© rĂ©duit de (4,5225-4,04167)=0,48
seconde, soit le dĂ©marrage est plus rapide de â10,6% de la valeur initiale.
Analyse des résultats
Le titre de travail de l'article est: "Pourquoi si peu?"
Nous, comme, avons tout fait selon les instructions, mais toutes les classes n'étaient pas dans l'archive. Leur nombre affecte le temps de lancement non moins que la puissance de calcul de la machine de l'expérimentateur, nous allons donc nous concentrer sur ce nombre.
Si vous vous en souvenez, nous avons ignoré le fichier log/cds.log
créé lors de l'arrĂȘt de l'application expĂ©rimentale aprĂšs la pĂ©riode d'essai. Dans ce fichier HotSpot, la JVM a gentiment notĂ© les classes d'avertissement pour chaque classe qui n'apparaissait pas dans l'archive CDS. Voici le nombre total de ces marques:
grep -o '[warning]' cds.log -c 3591
Ătant donnĂ© que seules 10 000 classes et plus sont mentionnĂ©es dans le journal class-load.log
et que 66% d'entre elles sont téléchargées à partir de l'archive, il n'est pas difficile de comprendre que les 3600 classes répertoriées dans cds.log
représentent les 44% «manquants» du potentiel CDS. Vous devez maintenant découvrir pourquoi ils ont été ignorés.
Si vous regardez le journal cds.log, il s'avĂšre qu'il n'y a que 4 raisons uniques pour sauter des classes. Voici des exemples de chacun d'eux:
Skipping org/springframework/web/client/HttpClientErrorException: Not linked Pre JDK 6 class not supported by CDS: 49.0 org/jrobin/core/RrdUpdater Skipping java/util/stream/Collectors$$Lambda$554: Unsafe anonymous class Skipping ch/qos/logback/classic/LoggerContext: interface org/slf4j/ILoggerFactory is excluded
Parmi les 3591 classes manquées, ces raisons se retrouvent ici avec une telle fréquence:

Examinez-les de plus prĂšs:
Unsafe anonymous class
JVM ââ , -, .
Not linked
, ââ , , . , StackOverflow . , , ââ () JAR- , AppCDS. , ( ).
Pre JDK 6 class
, CDS Java 5. class- , CDS . , , 6, Java, . - , runtime- (, slf4j).
Skipping ... : super class/interface ... is excluded
, ââ . CDS', . Par exemple:
[warning][cds] Pre JDK 6 class not supported by CDS: 49.0 org/slf4j/spi/MDCAdapter [warning][cds] Skipping ch/qos/logback/classic/util/LogbackMDCAdapter: interface org/slf4j/spi/MDCAdapter is excluded
Conclusion
CDS 100%.
, , , , , . .
JEP-310 , AppCDS JDK. . , . CDS (, , ) .
Afin de cloner le lapin expĂ©rimental (exĂ©cuter AnaLog dans plusieurs cas), nous devons changer quelque chose dans les paramĂštres; cela permettra aux processus levĂ©s de ne pas «coude». GrĂące Ă Spring Boot, vous pouvez le faire sans modifier ni copier aucun fichier; tous les paramĂštres peuvent ĂȘtre remplacĂ©s par les options JVM. Le transfert de ces options Ă partir de la variable d'environnement ANALOG_OPTS
fournit un script de lancement, gentiment généré par Gradle.
export ANALOG_OPTS="-Djavamelody.enabled=false -Dlogging.config=classpath:logging/logback-console.xml" export ANALOG_OPTS="$ANALOG_OPTS -Dnodes.this.agentPort=7801 -Dserver.port=8091"
JavaMelody, , , . TCP- ; .
, , JVM AppCDS . JAVA_OPTS
JVM Unified Logging Framework :
export JAVA_OPTS="-Xlog:class+load=info:file=log/class-load-%p.log -Xlog:class+path=debug:file=log/class-path-%p.log" export JAVA_OPTS="$JAVA_OPTS -XX:SharedArchiveFile=work/classes.jsa"
%p
, JVM (PID). AppCDS , ( ).
, . . :
server.port
nodes.this.agentPort
, :
export ANALOG_OPTS="$ANALOG_OPTS -Dnodes.this.agentPort=7801 -Dserver.port=8091"
, ( ).
bin/analog
() http://localhost:8091 ,
PID ( ), :
pgrep -f analog 13792
pmap
( ):
pmap -XX 13792 | sed -n -e '2p;$p' Address Perm Offset Device Inode Size KernelPageSize MMUPageSize Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous LazyFree AnonHugePages ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked ProtectionKey VmFlagsMapping 3186952 1548 1548 328132 325183 3256 0 10848 314028 212620 314024 0 0 0 0 0 0 0 325183 0 KB
; .
1-4 (, ).
pmap
. CDS' . , , PSS:
The "proportional set size" (PSS) of a process is the count of pages it has in memory, where each page is divided by the number of processes sharing it. So if a process has 1000 pages all to itself, and 1000 shared with one other process, its PSS will be 1500.
, , â â . , .
PSS , :
, - :
, . AppCDS. , -XX:SharedArchiveFile=work/classes.jsa
-Xshare:off
, CDS . , .

:
PSS AppCDS CDS.
. , , HelloWorld- JVM CDS 2 , CDS. PSS CDS, . :
PSS AppCDS 2- ; 3- .
, , , . , AppCDS, , , 3- .
: , CDS? :
CDS/AppCDS JVM , PSS . , , pmap
, ââ sed
'. :
pmap -X `pgrep -f analog` 14981:
( Mapping
) , ââ . JVM ( libjvm.so
), ( libc-2.27.so
). :
For the Java VM, the read-only parts of the loaded shared libraries (ie libjvm.so
) can be shared between all the VM instances running at the same time. This explains why, taking together, the two VM's consume less memory (ie have a smaller memory footprint) than the simple sum of their single resident set sizes when running alone.
. , , . , , JVM , Java- . GeekOut:

, , , AppCDS , .. Java-. , JVM, , - .
VisualVM Metaspace AppCDS , :
AppCDS

AppCDS

, 128 Metaspace AppCDS 64.2 MiB / 8.96 MiB
â7,2 , CDS . (. ) 66.4 MiB / 13.9 MiB
â4,8 . , AppCDS , Metaspace. Metaspace, , CDS .
Au lieu d'une conclusion
Spring Boot AppCDS â JVM, .
- JEP-350 Dynamic CDS Archives â JDK 13.
- Spring Boot Ăł CDS ( ). , 100% - 66% . , â11% ( 15%, ).
- , 5- PSS ( ). , AppCDS , , 8% (PSS). , CDS, , . AppCDS .
- Metaspace, , AppCDS 5 , CDS.
, , AppCDS, , âkiller featureâ. Spring Boot. , , AppCDS . , , AppCDS Spring Boot. , âŠ
by Nick Fewings on Unsplash