L’extraction d’informations utiles de vos fichiers journaux est essentielle au succès de votre application Java. Les données de journal vous donneront des indications précieuses sur les performances, la stabilité et la convivialité de votre application.

L’analyse des données de journal peut sembler fastidieuse, mais elle ne doit pas l’être. Il existe une variété d’outils pour lire, analyser et consolider les données des journaux. Les outils de base en ligne de commande, tels que grep, uniq et sort, peuvent combiner et extraire des informations utiles des fichiers journaux. Des analyseurs de journaux plus avancés, tels que Logstash ou Fluentd, peuvent extraire les données clés de vos journaux en jetons facilement consultables. Les services de journalisation basés sur le cloud, tels que SolarWinds® Loggly®, stockent vos données de journal pour vous et offrent des capacités d’analyse sophistiquées, éliminant ainsi le besoin de maintenir les journaux vous-même.

Cette section explore certaines méthodes et outils d’analyse des journaux dans le but d’améliorer vos applications.

Détecter les exceptions les plus courantes

Détecter les exceptions les plus courantes peut vous aider à localiser les zones de mauvaises performances dans votre application Java. La plupart des cadres de journalisation enregistrent le type d’exception, le message d’exception et la méthode dans laquelle l’exception s’est produite. En utilisant Log4j, un journal d’exceptions ressemblera à l’un des suivants.

09:54:44.565 ERROR Log4jTest.MathClass - java.lang.ArithmeticException: / by zero10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: myFile (No such file or directory)10:00:10.157 ERROR Log4jTest.Log4jTest - java.io.FileNotFoundException: newFile (No such file or directory)

Si votre sortie inclut des traces de pile, consultez la section Analyser les traces de pile multilignes de ce guide.

Débutons par un exemple simple utilisant l’outil populaire GNU grep. Ensuite, nous montrerons comment un outil de gestion des journaux peut rendre les choses encore plus faciles.

Formation des exceptions par type à l’aide de grep

La commande Unix suivante trouvera des exceptions, extraira le type d’exception et comptera le nombre d’occurrences. grep est un outil de ligne de commande populaire qui effectue une correspondance de motifs, tandis que uniq et sort regroupent et trient les résultats, respectivement :

$ grep -o "\w*Exception" myLog.log | sort -r | uniq -c

Dans cet exemple, l’expression régulière \w*Exception correspond à tout mot qui se termine par « Exception ». L’indicateur -o indique à grep d’imprimer uniquement les parties de la sortie qui correspondent à la chaîne de recherche. sort -r trie le résultat dans l’ordre inverse, tandis que uniq -c regroupe les résultats et compte le nombre d’occurrences. En conséquence, nous nous retrouvons avec un compte des exceptions par type.

2 FileNotFoundException1 ArithmeticException

Nous pouvons également utiliser grep pour rechercher dans le journal chaque instance spécifique de ces exceptions.

$ grep ArithmeticException myLog.log09:54:44.565 ERROR Log4jTest.Log4jTest - java.lang.ArithmeticException: / by zero

Cela renvoie chaque ligne contenant une instance de la chaîne de recherche ArithmeticException, avec la chaîne de recherche elle-même mise en évidence dans la sortie.

Recherche d’exceptions par classe à l’aide de Grep

Vous pouvez également rechercher des exceptions par la classe dans laquelle elles se sont produites. Pour les événements de journal à ligne unique, la commande suivante regroupe le nombre d’exceptions par classe et par type. grep extrait le nom de la classe en recherchant un mot suivi d’un caractère particulier (cet exemple utilise un trait d’union, bien que n’importe quel caractère puisse être utilisé tant qu’il est unique à l’entrée). Bien que ce caractère ne soit pas essentiel, il nous aide à localiser le nom de la classe dans l’événement du journal. Avec l’opérateur OR (désigné par |), grep extraira également le nom de l’exception en recherchant un mot contenant la chaîne de caractères « Exception. »

sed est un autre utilitaire de ligne de commande qui peut être utilisé pour formater la sortie de grep. Dans cet exemple, sed supprime le caractère spécial de notre sortie ainsi que tous les caractères de nouvelle ligne. La sortie est ensuite acheminée vers les commandes uniq et sort pour respectivement regrouper et trier les résultats.

$ grep -o "w* -|\w*Exception" myLog.log | sed 'N; s/ -n/ /' | sort -r | uniq -c

Le résultat nous rapproche des zones de problèmes clés :

2 Log4jTest FileNotFoundException1 MathClass ArithmeticException

Avec ces résultats, nous pouvons utiliser grep pour trouver plus de détails sur les problèmes survenant dans des classes spécifiques. Par exemple, la commande suivante récupère les exceptions qui se sont produites dans la classe MathClass.

$ grep -e "MathClass.*Exception" myLog.log09:54:44.565 ERROR Log4jtest.MathClass - java.lang.ArithmeticException: / by zero

Utilisation d’une solution de gestion des journaux

La plupart des solutions de gestion des journaux offrent des moyens de regrouper et de rechercher des entrées de journal en fonction du type de journal, du contenu du message, de la classe, de la méthode et du thread. Si vos journaux sont déjà analysés et stockés, de nombreuses solutions peuvent établir des graphiques et trier les exceptions en fonction du nombre d’occurrences. Il s’agit d’une opération de type pointer-cliquer dans Loggly, ce qui vous évite d’avoir à mémoriser des commandes grep compliquées. Loggly indexe également les enregistrements du journal, ce qui rend les recherches et les comptages beaucoup plus rapides que grep. Par exemple, nous pouvons utiliser l’explorateur de champs pour voir une liste d’exceptions et leur fréquence, puis cliquer sur une exception pour afficher tous les journaux pertinents.

Utilisation de l’explorateur de champs de Loggly pour trouver rapidement des journaux par type d’exception.

Loggly offre également des outils de visualisation qui peuvent être plus informatifs que la sortie textuelle de grep. Des graphiques comme celui-ci peuvent vous aider à prioriser les ressources pour les sprints de développement ou pour les correctifs suivant une nouvelle version.

Charting des exceptions par fréquence dans Loggly.

Débogage des problèmes de production

Lorsqu’il s’agit de problèmes de production, le temps est essentiel. Une erreur critique dans votre application ne laissera pas seulement vos utilisateurs mécontents ; elle fera également baisser les ventes et réduira la confiance dans votre application ou service.

Dans la plupart des cas, la résolution d’un problème peut être décomposée en trois étapes clés :

  1. Recueillir des informations sur le problème
  2. Identifier la cause du problème
  3. Trouver une solution et empêcher le problème de se reproduire

Recueillir des informations sur le problème

La première étape consiste à recueillir des informations sur le problème. Rassemblez autant d’informations que possible – captures d’écran, rapports de crash, journaux, liens (pour les services web), etc… – pour aider à réduire les causes potentielles. Vous voudrez que l’utilisateur qui a rencontré le problème fournisse des informations détaillées sur l’événement, y compris : quand et où dans le programme le problème s’est produit, ses actions menant au problème, l’environnement d’exploitation et tout comportement étrange ou inhabituel du programme avant et après l’apparition du problème.

À partir de là, vous pouvez commencer à recueillir des informations sur les journaux. Si votre application est un service hébergé, commencez à récupérer les journaux des serveurs web et d’application. Si votre application est un logiciel distribué, demandez à l’utilisateur d’inclure les données de journal dans son rapport de bogue. Alternativement, si votre application envoie des événements de journal à un serveur de journal centralisé, alors vos journaux seront immédiatement disponibles.

Une fois que vous avez une quantité raisonnable de données concernant le problème, vous pouvez commencer à le traquer dans le code.

Identifier la cause du problème

Après avoir collecté des informations sur le problème, l’étape suivante consiste à identifier sa cause. Reproduire un bogue dans un environnement de développement est l’une des façons les plus simples de valider son existence, mais cela peut prendre du temps et ne pas fonctionner dans tous les cas. Disposer d’un ensemble complet de journaux vous amènera directement à la source du problème, ce qui vous fera gagner du temps et vous évitera des frustrations.

Un rapport de bogue vous donnera une idée générale de la nature du problème et de l’endroit où il s’est produit. En utilisant l’outil de gestion des journaux de votre choix, vous pouvez réduire votre recherche à un éventail plus restreint d’entrées de journaux en recherchant un jeton de données unique tel qu’un nom d’utilisateur, un ID de session ou un texte de message.

Exécutons un exemple de scénario pour montrer comment déboguer un système. Imaginons que nous ayons une interface web pour se connecter à distance à un site web. La page Web a un écran de connexion qui effectue une authentification de base en utilisant un nom d’utilisateur et un mot de passe. Les utilisateurs signalent qu’ils ne peuvent pas se connecter au site Web. La page Web accepte leur entrée mais échoue ensuite avec une erreur générique.

Un exemple de site Web signalant une erreur après une tentative de connexion.

Ce message ne nous donne pas beaucoup d’informations autres qu’une indication générique de la gravité du journal. La recherche dans un gestionnaire de journaux d’entrées avec « Severe » dans le niveau ou le message pourrait donner des centaines de résultats sans garantie qu’aucun d’entre eux soit lié au problème en question. Heureusement, notre Logger a également enregistré le nom d’utilisateur de l’utilisateur qui a rencontré l’erreur, nous pouvons donc filtrer sur le nom d’utilisateur « admin ».

Visualisation d’une exception Java dans Loggly.

Si nous creusons, nous voyons que la cause de l’erreur est une table manquante ou invalide. C’est un problème sérieux, car cela pourrait indiquer une suppression accidentelle ou une corruption de la base de données.

ERROR: Exception for user admincom.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'test_schema.users' doesn't exist...com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1651) at TestApplication.Test.doPost(Test.java:33) at javax.servlet.http.HttpServlet.service(HttpServlet.java:646) at javax.servlet.http.HttpServlet.service(HttpServlet.java:727) at...

En examinant la trace de la pile, nous voyons que le service a échoué à la ligne 33 de Test.java. Cette ligne consiste en une instruction SQL qui tire des données sur un utilisateur de la table test_schema.users.

rs = stmt.executeQuery("SELECT * FROM test_schema.users WHERE username = " + username + " AND Password = " + password);

Lorsque nous essayons d’exécuter cette requête dans un front-end SQL, nous constatons que la table « test_schema.users » n’existe pas. Cependant, la base de données possède bien une table « test_schema.user ». À un moment donné, un développeur a peut-être saisi par erreur le mauvais nom de table et a envoyé le formulaire révisé en production. Maintenant, nous savons quel est le problème et où il apparaît dans notre code.

En utilisant SolarWinds Loggly, vous pouvez déboguer et trouver la cause profonde des problèmes en traçant les erreurs à travers votre pile d’applications, à travers plusieurs événements de journal, et même en localisant la ligne de code pertinente dans GitHub.

Résoudre le problème et empêcher qu’il ne se reproduise

Maintenant que nous avons identifié le problème et sa cause, l’étape finale consiste à le résoudre. Notre exemple de connexion était un cas exagéré avec une solution relativement facile, mais vous pouvez rencontrer des bugs plus compliqués enracinés dans différentes zones de votre application. Avant de sauter sur la solution rapide et sale, examinez attentivement l’impact de votre changement sur l’application. S’agit-il vraiment de la meilleure solution pour résoudre le problème ? Est-il possible que votre changement interfère avec un autre composant ? Ce correctif rendra-t-il difficile l’introduction de nouveaux correctifs ou de nouvelles fonctionnalités à l’avenir ? Ce correctif empêchera-t-il également des problèmes similaires de se présenter plus tard ?

Par exemple, que se passe-t-il si deux utilisateurs différents parviennent à créer deux comptes distincts avec le même nom d’utilisateur et le même mot de passe ? Vous pourriez imposer un nom d’utilisateur unique pour tous les utilisateurs, mais comment cela affecterait-il la structure de votre base de données, votre code d’authentification et votre base d’utilisateurs existante ? Vous pourriez ajouter un nouveau champ unique, comme l’adresse électronique, et le rendre obligatoire, mais que faire si certains de vos utilisateurs actuels n’ont pas fourni d’adresse électronique ? Et si certaines adresses électroniques sont partagées entre plusieurs comptes ? Comment ces nouvelles règles affecteront-elles vos pages d’inscription, de recherche et d’administration ?

Vous devrez également tenir compte du délai entre la création d’une correction et son déploiement. Dans un environnement d’entreprise, votre code devra être revu par d’autres développeurs, intégré dans la base de code, construit, testé par l’assurance qualité, mis en scène, et peut-être passer par plusieurs autres étapes avant d’être mis en production. Votre entreprise peut avoir des protocoles spécifiques pour les bugs critiques ou urgents que vous devez suivre. Une fois que vous avez trouvé une solution, incluez-la dans votre documentation, ainsi que toute solution de contournement raisonnable du problème. De cette façon, vos clients peuvent toujours utiliser votre produit et votre équipe de support peut réduire le nombre de rapports de bogues en double pendant que la correction fait son chemin vers la production.

Après avoir déployé la correction, continuez à surveiller votre application de production pour vérifier que le problème a été résolu. Par exemple, après avoir déployé le correctif pour le problème de base de données dans l’exemple ci-dessus, nous ne devrions plus voir d’événements avec « Table ‘test_schema.users’ doesn’t exist ». Si les erreurs persistent ou si nous commençons à en voir de nouvelles, nous savons que la correction n’a pas fonctionné. Idéalement, nous verrons un modèle comme celui présenté dans la capture d’écran suivante, où le nombre d’erreurs tombe à zéro immédiatement après le déploiement du correctif.

Charting du nombre de journaux contenant une erreur dans Loggly.

Plus d’outils de débogage de production

Bien que la journalisation soit la méthode éprouvée de dépannage et de débogage des applications, ces outils peuvent vous aider à mieux comprendre le fonctionnement de votre application.

jdb

jdb, le débogueur Java, est un utilitaire en ligne de commande pour déboguer les classes Java. jdb est facile à utiliser et est fourni avec le kit de développement Java. L’utilisation de jdb crée une nouvelle machine virtuelle Java (JVM), ce qui vous permet de déboguer une classe sans affecter les programmes en cours d’exécution. Vous pouvez également utiliser jdb pour déboguer des applications en cours d’exécution en ajoutant les paramètres suivants à votre commande java :

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n

Lorsque la JVM démarre, elle attribue un numéro de port pour les connexions jdb entrantes. Vous pouvez ensuite vous attacher à l’instance JVM en cours d’exécution en utilisant jdb -attach:

$ jdb -attach

Vous pouvez utiliser ceci, par exemple, pour connecter votre débogueur à une instance de production en cours d’exécution. Faites attention à l’utilisation de points d’arrêt dans ce scénario, car cela pourrait mettre en pause un thread actif. Cela peut avoir des conséquences si, par exemple, un client utilise l’application pendant que vous la déboguez. Pour plus d’informations, consultez la documentation Java sur jdb.

OverOps

OverOps est une suite d’outils pour surveiller les applications, analyser le code et détecter les problèmes. Contrairement aux logiciels de journalisation, qui reposent sur la sortie générée par une application en cours d’exécution, OverOps se connecte directement à la machine virtuelle Java pour cartographier la base de code de l’application, lire les variables et enregistrer les erreurs. Cela lui permet d’attraper plus d’erreurs et d’enregistrer plus de données que même le cadre de journalisation de l’application. OverOps utilise un modèle de logiciel en tant que service (SaaS), où les mesures sont collectées et stockées sur les serveurs en nuage d’OverOps. Cependant, vous pouvez également le déployer sur site. Dans les deux cas, vous pouvez visualiser vos données à l’aide d’une interface Web.

BTrace

BTrace est un outil de traçage qui vous permet de surveiller tous les aspects de votre application, des noms de classe aux erreurs. BTrace utilise une approche de programmation orientée aspect impliquant l’utilisation d’annotations, qui spécifient où et comment BTrace surveille votre application. Par exemple, le script BTrace suivant surveille et consigne chaque appel au paquet javax.swing.

import com.sun.btrace.annotations.*;import static com.sun.btrace.BTraceUtils.*; @BTrace public class AllMethods { @OnMethod( clazz="/javax\.swing\..*/", method="/.*/" ) public static void m(@ProbeClassName String probeClass, @ProbeMethodName String probeMethod) { print(Strings.strcat("entered ", probeClass)); println(Strings.strcat(".", probeMethod)); }}

Pour plus d’informations sur BTrace, consultez le dépôt GitHub et le Wiki de BTrace.

Chronon

Chronon vous permet de rembobiner et de lire le flux d’exécution complet d’une application. Il enregistre chaque changement individuel effectué pendant la durée de vie d’une application, vous permettant de reproduire l’état de l’application à tout moment. Les enregistrements sont sauvegardés dans un fichier, ce qui facilite le transfert de l’historique d’exécution d’une machine de production à une machine de développement pour les tests.

Chronon se compose du Chronon Recording Server, qui vous permet d’enregistrer des applications Java à distance ; de Embedded Chronon, qui intègre l’enregistreur à l’intérieur d’une application ; et du Time Travelling Debugger, qui vous permet de rejouer les enregistrements.

jhsdb

jhsdb (Java HotSpot Debugger) est une suite d’outils de débogage, d’analyse et de profilage de la JVM par défaut fournie à la fois avec OpenJDK et le JDK d’Oracle. jhsdb vous permet de vous attacher aux processus Java en cours d’exécution, de prendre des instantanés des traces de la pile et même d’analyser les JVM en panne. Vous pouvez l’utiliser pour accéder au tas, au cache de code, aux statistiques de garbage collection, et plus encore. Pour en savoir plus, consultez la page de documentation jhsdb.

Tracer les transactions

Lorsqu’un problème survient, il est important de savoir où le problème a commencé et comment il a affecté le reste de votre application. C’est déjà difficile dans une application monolithique, mais cela devient encore plus difficile dans une architecture distribuée orientée services, où une seule requête peut toucher des dizaines de services. Il n’est pas toujours évident de savoir quel service est à l’origine de l’erreur, ou comment celle-ci a affecté les autres services. Le traçage fournit les données nécessaires pour suivre le chemin d’exécution de votre application et creuser jusqu’à la cause exacte d’un problème.

Dans la section Débogage des problèmes de production du guide, nous avons parcouru un exemple où un utilisateur avait des difficultés à se connecter à une application Web en raison d’une table de base de données invalide. Dans cette section, nous allons montrer comment le traçage des transactions a joué un rôle central dans la résolution du problème.

Traçage des identifiants uniques

Afin de tracer une séquence d’événements de journal, vous avez besoin d’un moyen d’identifier de manière unique les journaux liés. Un environnement multi-utilisateurs pourrait générer des centaines de journaux identiques, rendant difficile la recherche basée sur l’horodatage ou Logger. Une solution plus simple consiste à inclure un identifiant unique avec les entrées de journal liées. Cet identifiant peut être un nom d’utilisateur, un identifiant de session, une clé API ou un identifiant unique universel (UUID). Heureusement, ThreadContext est parfaitement adapté à ce travail.

Dans l’exemple du débogage des problèmes de production, nous avions une interface utilisateur Web qui était hébergée dans un servlet Tomcat, qui se connectait à une base de données MySQL. Les utilisateurs saisissaient leurs informations d’identification sur la page Web, et après avoir appuyé sur soumettre, le servlet exécutait une requête comparant leurs informations d’identification à celles stockées dans la base de données. Si l’utilisateur est authentifié, il est redirigé vers la page principale. Si une erreur se produisait, les détails de l’erreur étaient enregistrés et les utilisateurs recevaient un message générique.

Nous avons pu déboguer ce problème en incluant les noms d’utilisateur des utilisateurs dans le message du journal. Cela nous a permis de rechercher rapidement les événements de journal liés à l’utilisateur admin. À partir de ce même exemple, nous pouvons utiliser ThreadContext.put() pour associer un nom d’utilisateur à un Logger. Lorsque les utilisateurs soumettent leurs informations d’identification, le servlet entre dans la méthode doPost(), qui ajoute les noms d’utilisateur des utilisateurs au ThreadContext :

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {ThreadContext.put("username", request.getParameter("username"));logger.info("Entering doPost().");...}

L’utilisation de Log4j avec le motif %p : %m%n donne l’entrée suivante :

INFO : Entering doPost().

Nous pouvons ajouter des événements similaires pour accéder à la base de données MySQL, quitter la méthode doPost et effectuer d’autres actions. De cette façon, si l’utilisateur déclenche une exception, nous savons exactement ce qu’il faisait lorsque l’exception s’est produite.

Traçage des appels de méthode

Plusieurs frameworks de journalisation fournissent des méthodes natives pour tracer le chemin d’exécution d’une application. Ces méthodes varient légèrement entre les frameworks, mais suivent le même format général.

  • traceEntry() marque le début d’une méthode.
  • traceExit() marque la fin d’une méthode. Pour les méthodes qui renvoient un objet, vous pouvez simultanément renvoyer l’objet et enregistrer l’événement avec return logger.exit(object).
  • throwing() marque une exception qui n’est pas susceptible d’être traitée, comme un RuntimeException.
  • catching() marque une exception qui ne va pas être rejetée à nouveau.

Vous pouvez trouver des informations spécifiques au framework sur ces méthodes dans la documentation du Logger pour Log4j, Logback et java.util.logging.

Méthodes de traçage dans Log4j

A titre d’exemple d’utilisation de Log4j, nous allons remplacer les méthodes Logger.info() de notre servlet par des méthodes de traçage.

public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { logger.entry(); ... logger.exit();}

Nous changerons également le Appender's PatternLayout pour montrer le nom de la classe, la méthode et le numéro de ligne (les modèles de conversion %class, %M et %line).

<PatternLayout pattern="%p %class %M %line: %m%n" />

Les méthodes de traçage enregistrent les événements au niveau TRACE, ce qui signifie que nous devrons changer le niveau Logger's de DEBUG à TRACE. Sinon, les messages de journal seront supprimés.

<Loggers> <Root level="trace"> <AppenderRef ref="Console"/> </Root></Loggers> TRACE DatabaseApplication.Login doPost 26: entry...TRACE DatabaseApplication.Login doPost 59: exit

Les méthodes de traçage fournissent également leurs propres Markers. Par exemple, les méthodes Logger.entry() et Logger.exit() affichent respectivement ENTER et EXIT.

ENTER 14:47:41.074 TRACE DatabaseApplication.Login - EnterEXIT 14:47:41.251 TRACE DatabaseApplication.Login - Exit

Méthodes de traçage dans SLF4J

Les utilisateurs de SLF4J peuvent profiter de MDC pour tracer les événements de journal. Comme pour Log4j, les valeurs MDC peuvent être utilisées avec un Appender en utilisant le modèle de conversion %X.

SLF4J fournit également des méthodes entry(), exit(), throwing(), et catching() à travers la classe XLogger (Extended Logger). Vous pouvez créer une instance XLogger en utilisant XLoggerFactory.getXLogger().

package DatabaseApplication;import org.slf4j.Logger;import org.slf4j.LoggerFactory; import org.slf4j.ext.XLogger;import org.slf4j.ext.XLoggerFactory; public class Login extends HTTPServlet { final static XLogger xlogger = XLoggerFactory.getXLogger(Login.class.getName()); final static Logger logger = LoggerFactory.getLogger(Login.class.getName()); @Override public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { xlogger.entry(); .. xlogger.exit(); }}

Ajouter les motifs de conversion %class et %line à logback.xml.

<configuration> <appender name="Console" class="ch.qos.Logback.core.ConsoleAppender"> <encoder> <pattern>%-5level %class{36} %M %L: %msg%xEx%n</pattern> </encoder> </appender> <root level="trace"> ... </root></configuration>

Les entrées de journal résultantes sont identiques à celles créées par Log4j.

Gérer l’utilisation de la mémoire

La gestion de la mémoire est souvent négligée dans les langages de plus haut niveau tels que Java. Bien que la quantité moyenne de mémoire dans les appareils modernes augmente, une utilisation élevée de la mémoire peut avoir un impact important sur la stabilité et les performances de votre application. Une fois que la machine virtuelle Java ne peut plus allouer de mémoire à partir du système d’exploitation, votre programme peut s’arrêter et planter. Savoir comment gérer la mémoire permettra d’éviter les problèmes à mesure que la taille de votre application augmente.

Par exemple, imaginons que nous voulions stocker un ensemble de chiffres à partir de un. Un utilisateur fournit une limite supérieure et le programme stocke chaque nombre entier de « 1 » à cette limite. Nous utiliserons une boucle while avec un compteur pour ajouter chaque nombre à un tableau.

import java.util.Scanner;...System.out.print("Please enter the maximum size of the array: ");Scanner scanner = new Scanner(System.in);int limit = scanner.nextInt(); ArrayList intArray = new ArrayList(); int count = 1;while (count <= limit) { intArray.add(count);}

Vous avez peut-être remarqué que count ne s’incrémente pas dans la boucle. C’est un gros problème ; si l’utilisateur entre un nombre supérieur à zéro, le tableau continuera à croître jusqu’à ce que la JVM utilise toute sa mémoire disponible et que le programme se plante.

Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceat java.util.Arrays.copyOf(Arrays.java:2245)at java.util.Arrays.copyOf(Arrays.java:2219)at java.util.ArrayList.grow(ArrayList.java:242)at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)at java.util.ArrayList.add(ArrayList.java:440)at MemoryTest.main(MemoryTest.java:10)

Collecte de déchets

Pour réduire l’utilisation de la mémoire, la machine virtuelle Java effectue un processus de nettoyage périodique connu sous le nom de collecte de déchets. Le ramassage des ordures recherche les blocs de mémoire qui ne sont plus utilisés et les rend disponibles pour une réutilisation. Les ressources suivantes expliquent plus en détail le processus de collecte des ordures de Java.

  • Notions de base sur la collecte des ordures de Java (Oracle)
  • Guide de réglage de la collecte des ordures de la machine virtuelle HotSpot (Oracle)
  • Comprendre les journaux GC G1 (Poonam Bajaj)
  • Guide de réglage de la collecte des ordures (Atlassian)

Le collecteur d’ordures génère des informations de diagnostic qui peuvent être utiles pour le profilage des performances des applications. Vous pouvez consigner ces informations en passant -Xlog:gc à la JVM lors du démarrage de votre application. Après chaque exécution, le ramasseur de déchets imprime des statistiques sur le processus de ramassage des déchets au format Unified JVM Logging. Voici un exemple.

 Using G1 Periodic GC disabled GC(0) Pause Young (Normal) (G1 Evacuation Pause) 7M->1M(64M) 8.450ms

Using G1 indique quelle méthode de ramassage des ordures est utilisée. Le collecteur Garbage-First (G1) est souvent activé par défaut sur les ordinateurs multiprocesseurs avec de grandes quantités de RAM. Periodic GC disabled indique que le processus de ramassage des ordures ne se répétera pas. La troisième ligne nous indique qu’il s’agit d’une pause d’évacuation, où les objets sont copiés entre les régions de mémoire selon qu’ils sont encore utilisés ou non. Pause Young nous indique que le processus a nettoyé la jeune génération, qui est l’endroit où les nouveaux objets sont alloués. En conséquence, l’utilisation totale de la mémoire par les objets de la jeune génération a chuté de 7M à 1M sur 64M alloués, et le processus a pris 8.450ms.

Avec le garbage collector qui imprime des informations de diagnostic sur la console, nous pouvons voir comment la quantité de mémoire allouée (la taille du tas) continue de croître au fil du temps. Nous enlèverons les temps CPU pour plus de simplicité.

$ java -Xlog:gc MemoryLeakDemo Using G1 Periodic GC disabled GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 25M->23M(64M) 4.372ms GC(1) Concurrent Cycle GC(1) Pause Remark 50M->34M(64M) 0.250ms GC(1) Pause Cleanup 94M->94M(124M) 0.057ms GC(1) Concurrent Cycle 169.695ms GC(2) Pause Young (Concurrent Start) (G1 Humongous Allocation) 94M->94M(124M) 3.738ms GC(3) Concurrent Cycle...

Chart montrant une augmentation progressive de l’utilisation du tas de la JVM au fil du temps.

Vous pouvez ajouter des horodatages à chaque entrée avec -XX:+PrintGCDateStamps et -XX:+PrintGCTimeStamps. Vous pouvez également enregistrer la sortie du garbage collector dans un fichier en passant-Xlog:gc:file : à la JVM lors du démarrage de votre application.

Si vous surveillez vos fichiers journaux avec rsyslog, vous pouvez ensuite transmettre les journaux à un système de journalisation centralisé où ils seront analysés et prêts pour une analyse en temps quasi réel. Voici à quoi ressemble un graphique chronologique dans Loggly. Il montre la taille totale du tas, ainsi que la taille du tas avant et après l’exécution du ramasse-miettes.

Fuites de mémoire

Une fuite de mémoire est une situation dans laquelle un programme alloue de la mémoire plus rapidement qu’il ne peut la libérer. La façon la plus simple de détecter une fuite de mémoire est lorsque votre programme ne répond plus, devient instable ou provoque des OutOfMemoryErrors. En Java, vous trouverez plus d’instances de collections Full GC à mesure que l’utilisation de la mémoire augmente.

Vous pouvez en savoir plus sur la sortie du garbage collector et sur la localisation des fuites de mémoire dans le chapitre Troubleshoot Memory Leaks de la documentation Java.

Ressources supplémentaires

Cut Debugging Time Without Writing a Single Line of Code (Loggly)-Guide d’utilisation de Takipi

The Ultimate Guide : 5 méthodes pour déboguer les serveurs de production à l’échelle (High Scalability)-Outils et techniques pour déboguer les problèmes de production

Gestion de la mémoire

Garbage Collection Tuning Guide (Oracle)-Guide pour comprendre et affiner le garbage collection de Java

Understanding Java Garbage Collection (CUBRID Blog)-Guide sur garb

See it. Analysez-le. Inspectez-le. Résolvez-le

Voyez ce qui compte.

DÉMARRER L’ESSAI GRATUIT

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.