Je pense que c'est très courant pour certaines personnes, mais en réalité, cela pose souvent des problèmes, et quand il s'agit de réglage Java, il existe de nombreuses méthodes de réglage orientées infrastructure telles que la modification des politiques GC, donc dans l'application Je décrirai principalement les choses de type TIPS qui peuvent être réalisées (d'après ce dont je me souviens ...).
--Problème: OutOfMemoryError, ralentissement --Cause: Génération en masse de chaîne --Solution: Compilez avec le dernier JDK, utilisez des classes d'édition de chaînes de longueur variable (StringBuffer, StringBuilder), etc.
** Détails ** Plus précisément, la description est la suivante. Je le vois souvent.
Chaîne Chaîne concaténée= "";
Chaîne concaténée= Chaîne concaténée +Chaîne de caractères supplémentaire 1;
Chaîne concaténée= Chaîne concaténée +Chaîne de caractères supplémentaire 2;
Chaîne concaténée= Chaîne concaténée +Chaîne de caractères supplémentaire 3;
Chaîne concaténée= Chaîne concaténée +Chaîne de caractères supplémentaire 4;
System.out.print(Chaîne concaténée);
(Les chaînes de caractères supplémentaires 1 à 4 sont des variables de type String. En premier lieu, je pense que vous pouvez utiliser + =, mais il y a beaucoup de gens qui écrivent de cette façon.)
Quelques jointures conviennent, mais même avec 5 ou 6 jointures, des problèmes peuvent survenir en fonction du nombre d'exécutions.
Dans le cas ci-dessus, une instance de la classe String est créée pour chaque concaténation, ce qui affecte le nombre d'occurrences GC en raison du grand nombre de petits objets Java générés. (Augmentation du nombre d'occurrences de GC ⇒ détérioration des performances) De plus, si un grand nombre d'instructions de boucle est généré, le nombre d'instances peut consommer la zone native de Java Heap. (Cela dépend de l'implémentation de la JVM)
Le remède est le suivant.
Chaîne Chaîne concaténée= "";
StringBuilder sb = new StringBuilder();
sb.append(Chaîne concaténée)
.append(Chaîne de caractères concaténée 1)
.append(Chaîne de caractères concaténée 2)
.append(Chaîne de caractères concaténée 3)
.append(Chaîne de caractères concaténée 4);
System.out.print(sb.toString());
(Bien que le coût de génération de StringBuilder augmente, abaisser le coût de génération de String est généralement plus efficace)
** Java récent semble souvent optimiser pour le code ci-dessus en optimisant au moment de la compilation **. Le réglage ici peut ne pas être nécessaire à l'avenir (il semble qu'il ne soit pas encore optimisé en fonction de la façon dont il est écrit, mais ...)
Si vous avez besoin de sécuriser le thread d'implémentation, utilisez StringBuffer au lieu de StringBuilder. (StringBuffer est un peu plus lourd car il prend en charge thread safe)
Si le nombre de jointures est connu à l'avance en dessous d'un certain niveau, la définition de la valeur initiale de StringBuilder peut améliorer les performances.
** Détails ** En tant que type souvent utilisé dans les applications métier, je pense que le côté de la chaîne de caractères est une valeur numérique ou une date, mais le problème se produit souvent avec la date. En effet, dans le cas de Java, le coût de génération est élevé car il y a accès au système d'exploitation lorsque la Date est New.
Cependant, étant donné que le système de date est souvent géré par la classe d'utilitaire et que la date est souvent générée (nouvelle date) dans l'utilitaire, si un grand nombre d'éléments de date sont traités dans une application métier avec de nombreux éléments, elle sera automatiquement répétée plusieurs fois. Cela peut entraîner une nouvelle date et de mauvaises performances.
En tant qu'expérience personnelle, par exemple, il y a les cas suivants.
Par exemple, la solution dans ce cas est la suivante.
--Ajoutez Date comme date système à la méthode de la classe d'utilitaire de date afin que Date soit générée à l'extérieur de l'utilitaire au lieu de l'intérieur. Cela limite le nombre de générations de date à une si la même date système est acceptable. ――Il est difficile d'ajouter des arguments, mais en réalité, s'il y a beaucoup de biais dans les variations d'entrée / sortie de l'utilitaire, donnez à la classe d'utilitaire un mécanisme de cache, et si les arguments de l'utilitaire sont les mêmes, sortez les informations du cache. Supprimer la nouvelle date (en supposant un cas où 3 modèles de dates sont générés en fonction du code produit, etc. en fonction de la date système)
--Problème: ressources insuffisantes de la destination de communication externe, détérioration de la vitesse
** Détails ** Lors de l'acquisition d'informations utilisateur ou d'informations contractuelles auprès de l'hôte (système hérité), l'hôte peut ne pas être en mesure de les récupérer si elles sont acquises à chaque fois. Dans ce cas, il n'est acquis qu'une seule fois lors de la connexion et les informations sont conservées en mémoire. Je pense que c'est quelque chose qui se fait dans un système normal, mais parfois, lorsque seul un traitement spécifique est omis ou qu'une nouvelle communication se produit, cela peut devenir un problème si une telle considération est omise. .. ..
De même, pour la communication avec la base de données, les éléments considérés comme immuables lors de la connexion, tels que les données de base, peuvent être mis en cache. Il existe deux modèles de mise en cache, l'un consiste simplement à le stocker dans les données de session et à l'avoir pour chaque utilisateur, et l'autre à le conserver dans une classe singleton et à l'avoir en commun pour tous les utilisateurs.
Ceux-ci ont le compromis d'une utilisation accrue de la mémoire, vous devez donc considérer la quantité de cache séparément. De plus, dans le passé, il est souvent devenu un goulot d'étranglement du serveur de base de données, mais récemment, les performances du serveur de base de données s'améliorent de plus en plus, et je pense qu'il existe de nombreux cas qui ont un mécanisme de cache tel que JPA à l'avance.
--Problème: OutOfMemoryError se produit, ce qui est très lent lorsqu'il s'agit de fichiers volumineux, etc. --Cause: l'API utilisée est inappropriée, la quantité de données gérées est importante et la surcharge de la JVM est fatale. --Solution: Optimiser l'API à utiliser, laisser le traitement du système d'exploitation
** Détails ** Il existe des cas tels que des problèmes de performances lors de la gestion de fichiers avec un volume de données de plusieurs centaines de M ou plusieurs G ou plus, principalement dans des lots Java, et des cas où OutOfMemoryError ne peut pas être utilisé en premier lieu.
Les cas suivants peuvent être considérés comme des contre-mesures.
Runtime runtime = Runtime.getRuntime();
runtime.exec("cat A fichier B fichier>Fichier concaténé");
(En plus de concachi, vous pouvez également utiliser la commande diff pour la comparaison de fichiers, awk pour le remplacement de chaîne, etc.)
Le problème avec cette méthode est qu'elle dépend du système d'exploitation, ce qui impose des restrictions sur la portabilité. Je voudrais l'appliquer au nombre minimum de places, ne pas l'appliquer à tous les lieux depuis le début. (Si l'environnement de test est Windows, la production est UNIX, etc., il est nécessaire de pouvoir renvoyer des commandes pour chaque environnement à l'emplacement d'implémentation approprié, etc.)
--Problème: dégradation des performances lors de l'accès à plusieurs utilisateurs en raison du traitement de synchronisation Java
** Détails ** Il existe une méthode qui contient un processus de synchronisation (bloc de synchronisation) pour gérer des tonnes uniques dans les classes d'utilitaires, etc., et lorsque vous copiez simplement ceci et créez une autre méthode, même si c'est une méthode qui ne nécessite pas de traitement de synchronisation Le bloc de synchronisation est décrit. Ou il est trop sécurisé, le bloc de synchronisation est trop large et des verrous sont très susceptibles de se produire. .. ..
La correspondance est simplement la suivante.
** Cependant, si vous réduisez trop le bloc de synchronisation, cela deviendra un problème thread-safe, vous devez donc être très prudent. ** S'il n'y a pas de problème, c'est aussi une bonne idée de ne pas répondre même s'il y a une description inutile. ..
--Problème: Le traitement est très lourd, mais il ne peut pas être traité par une petite main. Cependant, il n'y a pas d'exigences de traitement synchrone. --Solution: décale la synchronisation du traitement
** Détails ** Ce sera un changement au niveau de l'architecture, je voudrais donc éviter d'aller aussi loin, mais en réalité, je pense que cela peut être implémenté en fonction des résultats des tests de performance.
--Problème: Le traitement est très lourd, mais le traitement peut être parallélisé. De plus, il y a une marge en termes de ressources serveur. --Solution: Multiplexage du processus
** Détails ** Je suppose un lot, mais je pense qu'il y a des cas où il est mis en œuvre en ligne en combinaison avec la désynchronisation. Pour les applications qui ont une hypothèse de multiplexage, on recherche uniquement le degré optimal de multiplexage, mais si on veut supporter des applications qui n'ont pas d'hypothèse de multiplexage, ce sera aussi un changement au niveau de l'architecture, donc ce sera une modification majeure. .. ..
Vérifiez quel traitement est lourd, y compris l'application elle-même, le journal d'accès du serveur WEB et le journal de la destination de communication externe. Fondamentalement, je pense que la confirmation du journal est la plus haute priorité. (C'est la partie la plus difficile car vous ne pouvez pas vous connecter en production, mais ...)
C'est aussi un journal, mais dans le cas de Java, la dégradation des performances dans GC est le cas le plus courant, donc c'est spécial. Je pense que cela dépend de la JVM, mais en général, la fréquence GC, son type (avec ou sans Full GC), l'heure GC, etc. seront les points à vérifier.
Je pense qu'un moniteur de performances est préparé pour chaque système d'exploitation, vérifiez donc le processeur, la mémoire, l'accès au système d'exploitation, etc. Dans le cas des applications Java, il ne devrait pas y avoir de goulot d'étranglement de la mémoire du système d'exploitation, il s'agit donc principalement d'identifier s'il s'agit d'un goulot d'étranglement du processeur. Même si le CPU est à 100%, l'utilisation du CPU peut augmenter en raison de l'apparition fréquente de GC en raison d'un manque de mémoire, donc cela seul ne nous dit rien, mais ...
Si vous pouvez obtenir un vidage de thread, vous pouvez vérifier l'état interne de Java en obtenant un vidage de thread dans l'état de problème de performances. Pour les problèmes de chaîne, la majorité du nombre d'objets dans Heap est occupée par des chaînes String, et pour les problèmes synchrones, de nombreuses méthodes avec une clause de synchronisation dans les informations de thread sont occupées. , Etc. De plus, selon la JVM, il peut être possible d'obtenir des informations détaillées sur les informations sur les objets Java.
Recommended Posts