2010-08-27 18 views
1

J'ai un traitement par lots qui convertit WAV en MP3 séquentiellement. Le problème est qu'après quelques milliers, il y a trop de fichiers ouverts, et il se heurte à la limite du fichier.Comment tester le problème "Trop de fichiers ouverts"

La raison pour laquelle le fait est à cause du code dans SystemCommandTasklet:

FutureTask<Integer> systemCommandTask = new FutureTask<Integer>(new Callable<Integer>() { 
    public Integer call() throws Exception { 
     Process process = Runtime.getRuntime().exec(command, environmentParams, workingDirectory); 
     return process.waitFor(); 
    } 
}); 

Cela a pour effet secondaire méchant de me faire compte sur la machine virtuelle Java pour nettoyer les processus, en laissant les fichiers ouverts et tels.

Je l'ai réécrit pour être ainsi:

FutureTask<Integer> systemCommandTask = new FutureTask<Integer>(new Callable<Integer>() { 
    public Integer call() throws Exception { 
     Process process = Runtime.getRuntime().exec(command, environmentParams, workingDirectory); 
     int status = process.waitFor(); 

     process.getErrorStream().close(); 

     process.getInputStream().close(); 

     process.getOutputStream().flush(); 
     process.getOutputStream().close(); 

     process.destroy(); 

     return status; 
    } 

}); 

Je suis certain à 95% que cela fonctionne sur mon Mac (grâce à lsof), mais comment puis-je faire un test approprié qui fonctionnera sur n'importe quel système pour PROUVER que ce que j'essaye de faire fonctionne réellement?

Répondre

0

Une preuve sera difficile. Mais ...

Créez une commande (Dummy) qui ne fait pas grand-chose mais garde un verrou sur les fichiers, tout comme le vrai. Cela garantit que votre test ne dépend pas de la commande utilisée.

Créez un test qui démarre SystemCommandTask, en utilisant l'ancienne version, mais le DummyCommand. Faites-le démarrer la tâche souvent, jusqu'à ce que vous obteniez l'exception attendue. Appelons le nombre de Tâches nécessaires N

Changez le test pour démarrer 100xN Tâches.

Remplacez la tâche par la nouvelle version. Si le test devient vert, vous devriez être raisonnablement sûr que votre code fonctionne.

+0

Mon problème actuel est que la N semble être infini sur ma machine dev. –

+0

Si vous ne pouvez pas reproduire le problème sur votre système, vous avez besoin d'un système qui permet de reproduire le problème pour l'exécution du test. Ou une vérification si un fichier est réellement ouvert, mais je suppose que sur votre système, aucun fichier n'est laissé ouvert alors cela ne fonctionnerait pas non plus. –

0

Vous pourriez essayer de coder pour l'éviter. Pourquoi ne pas limiter de manière proactive le nombre de tâches à la fois, disons 100?

Dans ce cas, vous pouvez utiliser un mécanisme de pool pour exécuter votre travail comme les pools de threads.

+0

Je ne suis pas en cours d'exécution en parallèle, mais ... c'est juste un .exec après l'autre. Le problème est que, sauf si vous appelez explicitement process.destroy, vous dépendez de la JVM pour fermer le fichier. Si vous allez assez vite, vous allez submerger les limites de l'OS. –

+0

Ensuite, vous pouvez essayer de mettre en veille quelques secondes après chaque traitement (afer process.destroy). De cette façon GC devrait être exécuté. – YoK

1
  1. Vous ne devriez pas utiliser Runtime # exec() pour cela, car le processus n'est pas attaché à la JVM. Jetez un coup d'oeil sur le fichier j.l.ProcessBuilder qui retourne un processus qui est contrôlé par le processus de la JVM. Donc, le dumping du processus peut forcer le système à libérer/fermer des ressources.
  2. Vous devez également planifier et limiter les processus à l'aide de j.u.c.Executors.
  3. Vous pouvez également lire la limite en utilisant "ulimit -Sn" ("ulimit -Hn" ne devrait pas être préféré en raison de la santé du système;).
  4. Vérifiez votre outil qui convertit vos fichiers multimédias si elle conserve des ressources réservées après l'achèvement (fuites, attente pour les signaux de l'appelant, etc.).
+0

Ma première tâche, cependant, est de pouvoir recréer cette erreur sur commande sur n'importe quel système. Ca n'arrive jamais sur mon mac, jamais. et en changeant ulimit ou launchctl fait en fait la JVM pour nettoyer les poignées de fichiers plus rapidement! Les gens du lot de printemps ont écrit l'original, donc je me méfie de le changer bon gré mal gré. –

+0

De plus, ProcessBuilder me laisse avec le même problème. Comment puis-je prouver qu'appeler Process.destroy fait quoi que ce soit? –

+0

J'ai passé un peu de temps à considérer votre suggestion n ° 2, mais cela ne répond pas à ma question de savoir comment recréer/tester correctement. –