2009-11-02 6 views
8

Je travaille sur une énorme application Java héritée, avec beaucoup de choses manuscrites, que vous laisseriez gérer un framework.Trop de manipulateurs de fichiers ouverts

Le problème auquel je suis actuellement confronté est le manque de gestionnaires de fichiers sur notre serveur Solaris. J'aimerais savoir quelle est la meilleure façon de suivre les handles de fichiers ouverts? Où regarder et ce qui peut provoquer l'épuisement des handles de fichiers ouverts?

Je ne peux pas déboguer l'application sous Solaris, uniquement dans mon environnement de développement Windows. Est-il même raisonnable d'analyser les handles de fichiers ouverts sous Windows?

+1

avec un lsof -p PID, l'entrée la plus courante est la suivante: java 19157 dev 131u unix 105,98572 0t829 55050244/devices/pseudo/tl @ 0: ticots -> (socketpair: 0x1810c) (0x300199eed50) Une idée de ce que cela signifie et comment je peux le combattre? – dlinsin

Répondre

8

Une bonne chose que j'ai trouvé pour traquer les descripteurs de fichiers non fermée est FindBugs:

http://findbugs.sourceforge.net/

Il vérifie beaucoup de choses, mais l'un est la ressource opérations ouvrir/fermer le plus utile. C'est un programme d'analyse statique qui fonctionne sur votre code source et qui est également disponible en tant que plugin eclipse.

+0

En tant que témoignage personnel, j'ai rencontré un problème similaire à celui de l'OP (mon application lançait des exceptions car elle ne pouvait pas ouvrir plus de fichiers car j'avais trop de descripteurs de fichiers ouverts). L'exécution du code à l'aide de findbugs a permis d'identifier tous les endroits où les fichiers n'étaient pas fermés. Problème résolu! – tth

+0

Oui, cela m'a une fois aidé à trouver toute une série d'endroits où close() n'avait pas été appelé dans un bloc final approprié. – Benj

+0

bien qu'il n'ait pas résolu mon problème directement, c'était un bon indice! – dlinsin

0

Cela pourrait certainement vous donner une idée. Puisque c'est Java, la mécanique d'ouverture/fermeture de fichier doit être implémentée de la même façon (à moins qu'une des JVM ne soit implémentée de manière incorrecte). Je recommanderais d'utiliser File Monitor sur Windows.

1

Je commencerais par demander à mon administrateur système d'obtenir une liste de tous les descripteurs de fichiers ouverts pour le processus. Différents systèmes le font de différentes manières: Linux, par exemple, a le répertoire /proc/PID/fd. Je me souviens que Solaris a une commande (peut-être pfiles?) Qui fera la même chose - votre sysadmin devrait le savoir. Toutefois, à moins de voir beaucoup de références au même fichier, une liste fd ne va pas vous aider. Si c'est un processus de serveur, il a probablement beaucoup de fichiers (et de sockets) ouverts pour une raison. La seule façon de résoudre le problème est d'ajuster la limite du système sur les fichiers ouverts - vous pouvez également vérifier la limite par utilisateur avec ulimit, mais dans la plupart des installations actuelles, cela équivaut à la limite du système.

7

Sur Windows, vous pouvez regarder de fichiers ouverts en utilisant l'explorateur de processus:

http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx

Sur Solaris vous pouvez utiliser « lsof » pour surveiller les poignées fichier ouvert

+0

Merci! J'ai utilisé lsof, malheureusement il y a beaucoup de choses qui se passent et je ne sais pas vraiment comment limiter les résultats de lsof à ce qui est pertinent et ce qui n'est pas intéressant. – dlinsin

+1

Le résultat de Windows ne doit pas être extrapolé aux systèmes * nix. Ils ont un mécanisme différent d'ouverture de fichiers. –

1

Pas une réponse directe à votre question, mais ces problèmes peuvent être le résultat de la libération incorrecte des ressources de fichiers dans votre code existant. Par exemple, si vous travaillez avec des classes de FileOutputsStream assurez-vous que les méthodes proches sont appelés dans un bloc finally comme dans cet exemple:

FileOutputsStream out = null; 
try { 
    //You're file handling code 
} catch (IOException e) { 
    //Handle 
} finally { 
    if (out != null) { 
    try { out.close(): } catch (IOException e) { } 
    } 
} 
+0

Ce qu'il a dit. semble que les poignées de fichiers ne sont jamais libérées. – ChadNC

+0

Merci pour les conseils généraux, mais j'ai cherché toutes les occurrences de java.io. * et j'ai vérifié qu'elles sont dans un bloc try-catch-finally. – dlinsin

2

Pour répondre à la deuxième partie de la question:

ce qui peut provoquer des manipulations de fichiers à manquer?

Ouverture d'un grand nombre de fichiers, évidemment, et ne pas les fermer. Le scénario le plus simple est que les références à tous les objets contenant les poignées natives (par exemple FileInputStream) sont jetées avant d'être fermées, ce qui signifie que les fichiers restent ouverts jusqu'à la finalisation des objets.

L'autre option est que les objets sont stockés quelque part et non fermés. Un vidage de tas peut être en mesure de vous dire ce qui persiste où (jmap et jhat sont inclus dans le JDK, ou vous pouvez utiliser jvisualvm si vous voulez une interface graphique). Vous êtes probablement intéressé par la recherche d'objets possédant FileDescriptor s.

2

Ce petit script m'aide à garder un œil sur le nombre de fichiers ouverts lorsque j'ai besoin de tester le compte. Si a été utilisé sur Linux, Solaris, vous devez patcher (peut être :))

#!/bin/bash 
COUNTER=0 
HOW_MANY=0 
MAX=0 
# do not take care about COUNTER - just flag, shown should we continie or not 
while [ $COUNTER -lt 10 ]; do 
    #run until process with passed pid alive 
    if [ -r "/proc/$1" ]; then 
     # count, how many files we have 
     HOW_MANY=`/usr/sbin/lsof -p $1 | wc -l` 
     #output for live monitoring 
     echo `date +%H:%M:%S` $HOW_MANY 
     # uncomment, if you want to save statistics 
     #/usr/sbin/lsof -p $1 > ~/autocount/config_lsof_`echo $HOW_MANY`_`date +%H_%M_%S`.txt 

     # look for max value 
     if [ $MAX -lt $HOW_MANY ]; then 
      let MAX=$HOW_MANY 
      echo new max is $MAX 
     fi 
     # test every second. if you don`t need so frequenlty test - increase this value 
     sleep 1 
    else 
     echo max count is $MAX 
     echo Process was finished 
     let COUNTER=11 
    fi 
done 

Vous pouvez également essayer de jouer avec jvm ontion -Xverify: aucune - il devrait désactiver la vérification du pot (si la plupart des les fichiers ouverts sont des bocaux ...). Pour les fuites à travers FileOutputStream non fermé, vous pouvez utiliser findbug (encadré ci-dessus) ou essayer de trouver un article comment patcher FileOutputStream/FileInputStream java standard, où vous pouvez voir, qui ouvre les fichiers, et les oublier. Malheureusement, ne peut pas trouver cet article en ce moment, mais cela existe :) Pensez aussi à augmenter de filelimit - pour les noyaux nix * à jour n'est pas un problème gérer plus de 1024 fd.

2

Cela peut ne pas être pratique dans votre cas, mais ce que j'ai fait une fois quand j'ai eu un problème similaire avec les connexions de bases de données ouvertes, c'est remplacer la fonction "open" par la mienne. (Commodément, j'avais déjà cette fonction parce que nous avions écrit notre propre pool de connexion.) Dans ma fonction, j'ai ensuite ajouté une entrée à une table enregistrant l'ouverture. J'ai fait un appel de trace de pile et ai sauvé l'identification de l'appelant, avec le temps appelé et j'oublie quoi d'autre. Lorsque la connexion a été libérée, j'ai supprimé l'entrée de la table. Ensuite, j'ai eu un écran où nous pouvions vider la liste des entrées ouvertes. Vous pouvez alors regarder l'horodatage et voir facilement quelles connexions ont été ouvertes pour des durées improbables et quelles fonctions ont été ouvertes. À partir de là, nous avons été en mesure de localiser rapidement les deux fonctions qui ouvraient les connexions et ne parvenaient pas à les fermer.

Si vous avez beaucoup de handles de fichiers ouverts, il y a de fortes chances que vous n'ayez pas réussi à les fermer lorsque vous avez terminé. Vous dites que vous avez vérifié les blocs try/finally, mais je soupçonnerais que quelque part dans le code vous avez manqué un mauvais, ou que vous avez une fonction qui fait des mains et qui n'arrive jamais à la fin. Je suppose qu'il est également possible que vous fassiez des fermetures correctes chaque fois que vous ouvrez un fichier, mais que vous ouvrez des centaines de fichiers simultanément. Si c'est le cas, je ne suis pas sûr de savoir ce que vous pouvez faire d'autre qu'une refonte sérieuse du programme pour manipuler moins de fichiers, ou une refonte sérieuse du programme pour mettre en file d'attente vos accès au fichier. (À ce stade, j'ajoute l'habituel, "Sans connaître les détails de votre application, etc.)

1

Je revérifier les paramètres d'environnement sur votre boîte Solaris Je crois que par défaut, Solaris autorise seulement 256 handles de fichiers par Pour une application serveur, surtout si elle est exécutée sur un serveur dédié, la figure 50 ou plusieurs descripteurs pour ouvrir les JAR JRE et bibliothèque, puis au moins un descripteur pour chaque requête entrante et demande de base de données, probablement plus, et vous pouvez voir comment cela ne va pas couper la moutarde pour un serveur sérieux.

Jetez un oeil au fichier /etc/system, pour les valeurs de rlim_fd_cur et rlim_fd_max, voir ce que votre système a défini. Ensuite si cela est raisonnable (vous pouvez voir combien de descripteurs de fichiers sont ouverts alors que le serveur est en cours d'exécution avec la commande lsof, idéalement avec le paramètre [process ID] -p.

2

Sa valeur en gardant à l'esprit que sockets ouverts consomment également des handles de fichiers sur les systèmes Unix.Il pourrait donc s'agir d'une fuite de pool de connexion à une base de données (par exemple, les connexions à la base de données ouvertes ne sont pas fermées et renvoyées au pool), ce qui a déjà causé cette erreur.

0

Google pour une application appelée filemon à partir des internes du système.

BTW, pour suivre cela, vous pouvez utiliser quelque chose comme AspectJ pour enregistrer tous les appels qui ouvrent et ferment les fichiers et se connecter où ils se produisent.

+0

Et cela a été rejeté parce que? – vickirk

0

Il s'agit d'un modèle de codage qui aide à trouver des ressources non fermées. Il ferme les ressources et se plaint également dans le journal sur le problème. Enveloppez les appels file.close() ci-dessus dans des blocs try-catch qui ignorent les erreurs.

De plus, Java 7 dispose d'une nouvelle fonctionnalité 'try-with-resource' qui permet de fermer automatiquement les ressources.

+0

Son très mauvais design à utiliser finalize() http://www.informit.com/articles/article.aspx?p=1216151&seqNum=7 –

Questions connexes