Fuite de mémoire possible dans le nombre de classes chargées dans l'application Java

StackOverflow https://stackoverflow.com/questions/167740

  •  03-07-2019
  •  | 
  •  

Question

J'ai récemment commencé à profiler une application java osgi que j'écris à l'aide de VisualVM. Une chose que j'ai remarquée est que, lorsque l'application commence à envoyer des données à un client (via JMS), le nombre de classes chargées commence à augmenter à un rythme constant. La taille du tas et la taille de PermGen restent toutefois constantes. Le nombre de classes ne diminue jamais, même après la fin de l'envoi des données. Est-ce une fuite de mémoire? Je pense que oui, car les classes chargées doivent être stockés quelque part, mais le tas et le nombre de permgen n'augmentent jamais même après l'exécution de l'application pendant plusieurs heures.

Pour la capture d'écran de mon application de profilage, rendez-vous ici

Était-ce utile?

La solution

  

Créez-vous de manière dynamique de nouvelles classes à la volée?

Merci pour votre aide. J'ai compris quel est le problème. Dans l'une de mes classes, j'utilisais Jaxb pour créer une chaîne XML. Ce faisant, JAXB utilise la réflexion pour créer une nouvelle classe.

JAXBContext context = JAXBContext.newInstance(this.getClass());

Ainsi, bien que JAXBContext ne dise rien dans le tas, les classes avaient été chargées.

J'ai relancé mon programme et je constate un plateau normal, comme je le pensais.

Autres conseils

Je suis prêt à parier que votre problème est lié à la génération de bytecode.

De nombreuses bibliothèques utilisent CGLib, BCEL, Javasist ou Janino pour générer du code-octet pour les nouvelles classes au moment de l'exécution, puis les charger à partir d'un chargeur de classes contrôlé. Le seul moyen de libérer ces classes est de publier toutes les références au chargeur de classes.

Etant donné que le chargeur de classes est détenu par chaque classe, cela signifie également que vous ne devez pas publier les références à toutes les classes [1]. Vous pouvez les attraper avec un profileur correct (J'utilise Yourkit - recherche de plusieurs instances de chargeur de classe avec la même taille conservée)

Un problème est que la machine virtuelle Java ne décharge pas les classes par défaut (la raison en est une compatibilité ascendante: les utilisateurs supposent (à tort) que les initialiseurs statiques ne sont exécutés qu'une seule fois. La vérité est qu'ils sont exécutés chaque fois qu'une classe est chargée. .) Pour activer le déchargement, vous devez en transmettre quelques-unes aux options suivantes:

-XX:+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

(testé avec JDK 1.5)

Même dans ce cas, la génération excessive de bytecodes n’est pas une bonne idée. Je vous suggère donc de regarder dans votre code pour rechercher le coupable et mettre en cache les classes générées. Les contrevenants fréquents sont des langages de script, des proxys dynamiques (y compris ceux générés par des serveurs d’applications) ou un énorme modèle Hibernate (dans ce cas, vous pouvez simplement augmenter votre permen).

Voir aussi:

  1. http://blogs.oracle.com/watt/resource /jvm-options-list.html
  2. http://blogs.oracle.com/jonthecollector/entry/presenting_the_permanent_generation
  3. http://forums.sun.com/thread.jspa?messageID=2833028

Vous pouvez trouver certains indicateurs de points d'accès utiles pour comprendre ce comportement, tels que:

  • -XX: + TraceClassLoading
  • -XX: + TraceClassUnloading

C’est une bonne référence:

http://java.sun.com/javase/technologies/hotspot /vmoptions.jsp

À moins que je ne comprenne mal, nous examinons ici les classes chargées, et non les instances.

Lorsque votre code fait pour la première fois référence à une classe, la machine virtuelle Java demande au ClassLoader de rechercher les informations sur la classe dans un fichier .class ou similaire.

Je ne sais pas dans quelles conditions cela déchargerait une classe. Certes, il ne faut jamais décharger une classe d'informations statiques.

Je m'attendrais donc à un modèle similaire au vôtre, dans lequel votre application s'exécute dans des zones et référence de nouvelles classes, de sorte que le nombre de classes chargées augmente et augmente.

Cependant, deux choses me semblent étranges:

  1. Pourquoi est-ce si linéaire?
  2. Pourquoi ça ne se plateau pas?

Je pense que la tendance sera à la hausse, mais dans une ligne vacillante, puis à la baisse, car la JVM a déjà chargé la plupart des classes référencées par votre programme. Je veux dire, il y a un nombre fini de classes référencées dans la plupart des applications.

Créez-vous de manière dynamique de nouvelles classes à la volée?

Je suggérerais de lancer une application de test plus simple via le même débogueur pour obtenir un scénario de base. Ensuite, vous pouvez envisager de mettre en œuvre votre propre ClassLoader qui génère des informations de débogage, ou peut-être existe-t-il un outil pour le signaler.

Vous devez savoir quelles sont ces classes en cours de chargement.

Oui, il s’agit généralement d’une fuite de mémoire (puisque nous ne traitons pas directement avec la mémoire, c’est davantage une fuite d’instance de classe). Je suis déjà passé par ce processus et généralement, c'est un auditeur ajouté à une vieille boîte à outils qui ne l'a pas supprimé lui-même.

Dans le code plus ancien, une relation d'écouteur entraînait le " écouteur " objet à rester autour. Je regarderais les boîtes à outils plus anciennes ou celles qui n'ont pas connu beaucoup de révolutions. Toute bibliothèque existant de longue date et exécutée sur un JDK ultérieur connaîtrait les objets de référence, ce qui supprime la nécessité de "Supprimer l’écoute".

Appelez également dispos sur vos fenêtres si vous les recréez à chaque fois. Je ne pense pas qu'ils disparaissent jamais si vous ne le faites pas (en fait, il y a aussi une disposition sur proximité).

Ne vous inquiétez pas des auditeurs Swing ou JDK, ils devraient tous utiliser des références, donc tout devrait bien se passer.

Utilisez le Eclipse Memory Analyzer pour rechercher des classes dupliquées et des fuites de mémoire. Il peut arriver que la même classe soit chargée plus d'une fois.

Cordialement, Markus

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top