2011-05-12 1 views
6

Je rencontre un problème très étrange avec une application Java fonctionnant sous Tomcat.Débogage d'une fuite de mémoire étrange - Java/Tomcat

Nous avons essayé de mettre à jour le code de production à partir d'un nouveau produit dans un sprint d'une semaine, l'application a fonctionné pendant des mois sans hoquet et ce nouveau code a changé nos serveurs Linux. La chose très étrange est que lorsque vous regardez VisualVM pour l'utilisation de la mémoire, il ne dépasse jamais la taille maximale du tas, la JVM ne lance pas OutOfMemory, la machine commence seulement à échanger et la JVM continue à fonctionner même après cela. Donc, il semble que la mémoire fuit de quelque part, il semble que ce soit à partir du nouveau code, mais il est étrange que ce n'est pas dans la JVM, des idées sur la façon de déboguer cela?

Merci!

+0

Peut être utile pour afficher le code. – soandos

+0

Tout code natif impliqué (via JNI ou JNA), ou est-ce Java pur? – QuantumMechanic

+0

Serait-ce dû à des fichiers mappés en mémoire? Que montre 'top' pour l'utilisation de la mémoire du processus' java'? –

Répondre

2

L'échange n'est pas un indicateur concluant de fuite. Il résulte de la mémoire physique faible. Utilisez vmstat sous Linux pour obtenir l'utilisation de l'échange. Essayez d'utiliser une machine différente, expérimentez avec des configurations - taille de la mémoire, taille de la mémoire physique, espace d'adressage.

Si vous êtes certain que le problème est dans votre programme, essayez ceci:

  1. Estimation de la médiane et la mémoire de pointe que votre utilisation programme devrait. Vous devez être en mesure de comptabiliser tous les écarts par rapport à ces statistiques. Si vous ne le pouvez pas, passez à l'étape 3.

  2. En supposant que vous ayez correctement exécuté l'étape 1 et que vous étiez en mesure de prendre en compte toutes les déviations, vous pouvez exclure la fuite (désolé pour ces suggestions vagues mais le débogage est aussi bon que le détective). Vous devriez maintenant vous concentrer sur le réglage du GC. D'abord, activez la journalisation GC. Voyez si votre tas est plein et où le GC passe la plupart de son temps à collectionner. This peut être un bon point de départ pour démarrer les optimisations. Essayez de voir si l'ajustement des options du GC aide. Essayez d'expérimenter avec des algorithmes de collecte, des tailles de tas max/min, des rapports de génération, etc. N'expérimentez que lorsque vous avez exclu une fuite (étape 1).

  3. En supposant que vous avez correctement exécuté l'étape 1 et que vous n'avez pas pu prendre en compte tous les écarts, vous pouvez supposer que vous avez une fuite quelque part. Utilisez un profileur de mémoire pour voir quels objets contribuent le plus à la croissance de la taille de segment. Laisser un profileur s'exécuter pendant une période de temps prolongée - votre programme doit gérer certaines requêtes qu'il s'attend habituellement à obtenir et ensuite le laisser relativement isolé après cela. Si le niveau de mémoire ne cesse de croître, vous pouvez avoir une fuite quelque part. Sinon, ce n'est probablement pas une fuite de mémoire. Pouvez-vous identifier la partie de votre programme qui pourrait les créer? Si oui, essayez d'envoyer plusieurs demandes qui ne ciblent que cette partie de votre programme. Représente-t-il le problème de façon déterministe? Si non, répétez l'étape 3. Si oui, utilisez diviser pour régner et réappliquez l'étape 3 jusqu'à ce que vous puissiez trouver la classe/méthode qui sont les coupables. Il peut s'agir d'une certaine combinaison de plusieurs parties (ce qui signifie que, individuellement, elles peuvent sembler innocentes mais, ensemble, elles peuvent former un syndicat du crime brillant).

J'espère que cela aide, sinon alors s'il vous plaît laissez un commentaire à mon poste.

Tout le meilleur de votre exercice!

+0

Je vous remercie beaucoup pour cette étape-par-étape ... C'est tout ce que je sais devrait être fait mais je dois être rappelé de temps en temps. J'étais fatigué de déboguer la semaine dernière et n'ai pas eu l'état d'esprit pour commencer le débogage comme ça, je suis en train de le faire et de regarder si c'est vraiment une fuite dans l'application ou ailleurs dans le système d'exploitation. – victorcampos

+0

Hé, pas de problème. –

1

Je vous suggère de vous lancer dans la création de dumps sans utiliser jvisualvm. Pour les JVM Oracle basées sur Unix, ceci est normalement effectué en envoyant un signal 3 à la JVM en utilisant kill.

Pour plus de détails voir http://www.startux.de/index.php/java/45-java-heap-dumpyvComment45

Vous pouvez alors voir si les changements de modèles. Si vous n'avez aucune idée de cela, c'est peut-être parce que vous stockez une sous-chaîne à partir d'une très grande chaîne originale (qui porte le tableau de chaînes sous-jacent), ou parce que vous gardez le système d'exploitation des ressources telles que des connexions de base de données ouvertes, etc.

Vous avez vérifié que votre piscine de connexion a l'air bien?

0

Si vous ne l'utilisez pas, je vous recommande d'utiliser visual VM version 1.3.2 et tous les plug-ins. C'est un gros bond par rapport aux versions précédentes. Qu'arrive-t-il à l'espace perm générique?

Quels sont les paramètres de mémoire que vous utilisez? Min et max, bien sûr, mais qu'en est-il de la taille de l'espace perm?