2010-09-14 20 views
5

Tengo algunos problemas con respecto a ProcessBuilder. El programa es básicamente un envoltorio simple que invoca un script de línea de comandos.java: ProcessBuilder hace una memoria de cerdo

Al ejecutar el script solo a través del terminal, el consumo de memoria se mantiene por debajo de 2G. Al ejecutar el script a través del contenedor java, el consumo de memoria explota e incluso 8G se llena rápidamente, lo que produce errores de memoria insuficiente.

El código para poner en marcha el proceso es simple:

public static int execute(String command) throws IOException 
{ 
    System.out.println("Executing: " + command); 

    ProcessBuilder pb = new ProcessBuilder(command.split(" +")); 
    Process p = pb.start(); 

    // display any output in stderr or stdout 
    StreamConsumer stderr = new StreamConsumer(p.getErrorStream(), "stderr"); 
    StreamConsumer stdout = new StreamConsumer(p.getInputStream(), "stdout"); 
    new Thread(stderr).start(); 
    new Thread(stdout).start(); 

    try { 
    return p.waitFor(); 
    } catch (InterruptedException e) { 
    throw new RuntimeException(e); 
    } 
} 

clase El StreamConsumer es simplemente una clase que consume las corrientes/stderr stdout y mostrarlos en la consola.

... la pregunta es: ¿por qué el consumo de memoria explota?

Saludos,
Arnaud

Editar:

  • Si utilizo ProcessBuilder o Runtime.getRuntime.exec (...), el resultado es el mismo .
  • La memoria estallidos tienden a aparecer durante Unix 'especie' invocada por el guión shell llamado:
sort big-text-file > big-text-file.sorted 

Editar 2 en la petición de Jim Garrison:

Ok, aquí es la clase de StreamConsumer que omití porque es bastante simple:

class StreamConsumer implements Runnable 
{ 
    InputStream stream; 
    String descr; 

    StreamConsumer(InputStream stream, String descr) { 
     this.stream = stream; 
     this.descr = descr; 
    } 

    @Override 
    public void run() 
    { 
     String line; 

     BufferedReader brCleanUp = 
      new BufferedReader (new InputStreamReader (stream)); 

     try { 
      while ((line = brCleanUp.readLine()) != null) 
       System.out.println ("[" + descr + "] " + line); 
      brCleanUp.close(); 
     } catch (IOException e) { 
      // TODO: handle exception 
     } 
    } 
} 
+0

Solo una suposición: si StreamConsumer no consume el texto del subproceso, el texto se puede mantener en un búfer que aumenta constantemente de tamaño. –

+0

Todos stdout y stderr se muestran con éxito en la consola – dagnelies

+2

¿Cómo se está midiendo el consumo de memoria? _¿Qué proceso está consumiendo la memoria ... la JVM? ¿La cáscara? El proceso de clasificación? Sin ver StreamConsumer es difícil saber si hay algún error allí. ¿Está seguro de que el consumo de memoria es privado para el proceso o solo son búferes de E/S transitorias? Realmente no has proporcionado mucho para continuar aquí. –

Respuesta

2

si cambia su comando de esta manera: ordenar -o archivo de texto grande.sorted archivo de texto grande

¿es siempre lo mismo?

+0

Buen punto, quizás un error de redirección. Alguna reacción a esto? –

0

Tal vez sea porque esos hilos StreamConsumer no son daemons, por lo que no mueren y no se recogen cuando se recuperan los procesos. Puede intentar:

//... 
final StreamConsumer stderr = new StreamConsumer(p.getErrorStream(), "stderr"); 
final StreamConsumer stdout = new StreamConsumer(p.getInputStream(), "stdout"); 
final Thread stderrThread = new Thread(stderr); 
final Thread stdoutThread = new Thread(stdout); 
stderrThread.setDaemon(true); 
stdoutThread.setDaemon(true); 
stderrThread.start(); 
stdoutThread.start(); 
//... 

¿Este comportamiento ocurre para una invocación única o después de hacer esto muchas veces?

Cuestiones relacionadas