Evitar iniciar varias veces la máquina virtual Java para procesos cortos

Escrito por el .
java planeta-codigo programacion
Enlace permanente Comentarios

Java

Si en una aplicación o proyecto tenemos necesidad de ejecutar uno o varios procesos múltiples veces donde únicamente cambian los parámetros, de forma seguida y el tiempo de ejecución de esos procesos es corto probablemente quizá veamos que la mayor parte del tiempo empleado de los procesos sea empleado en iniciar la máquina virtual Java (JVM). Digo quizá porque usando Ubuntu en la nube de Amazon EC2 el tiempo de inicio era de varios segundos, sin embargo, en mi ordenador personal usando Arch Linux y con un disco SSD de Samsung los tiempos que obtengo son de unos pocos milisegundos, quizá la larga lista de dependencias del paquete de Java 7 en Ubuntu (probablemente del paquete openjdk-7-jre) y ocupando considerablemente más megas en disco tenga algo que ver:

Tiempo de inicio de la JVM

Por ejemplo, supongamos que tenemos unos procesos que tienen que ejecutarse de forma regular cada cierto tiempo variando los parámetros que se indica en cada uno de ellos. La ejecución de los procesos podría ser:

1
2
3
4
5
6
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v1 -p2 v2 -p3 v3
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v4 -p2 v5 -p3 v6
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v7 -p2 v8 -p3 v9
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v10 -p2 v11 -p3 v12
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v13 -p2 v14 -p3 v15
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v16 -p2 v17 -p3 v18
script-1.sh

A continuación pondré una idea para esta situación, quizá no es algo que se de muy a menudo pero en una ocasión esto me ha servido para evitar que el tiempo de inicio de la JVM sea el mayor tiempo empleado por los programas cortos. Consiste en iniciar una única máquina virtual para todos los procesos, con todos los parámetros de cada uno siendo el programa al iniciarse el que determine los parámetros de cada proceso individual. Por ejemplo, reescribiendo los ejemplos anteriores de la siguiente forma:

1
2
3
4
5
6
$ java -Xms256m -Xmx1536m -classpath $CLASSPATH io.github.picodotdev.script.Main -p1 v1 -p2 v2 -p3 v3 sep \
    -p1 v4 -p2 v5 -p3 v6 sep \
    -p1 v7 -p2 v8 -p3 v9 sep \
    -p1 v10 -p2 v11 -p3 v12 sep \
    -p1 v13 -p2 v14 -p3 v15 sep \
    -p1 v16 -p2 v17 -p3 v18
script-2.sh

Esto iniciará una única máquina virtual en vez de 6 de forma que evitemos mucho del tiempo empleado en el inicio de las JVM, dependiendo del tiempo empleado por los procesos el tiempo total posiblemente se reduzca considerablemente. Pasando todos los parámetros al único proceso deberemos determinar que parámetros son de cada uno, para ello en el ejemplo se usa el parámetro sep y la \ para poderlos ponerlos en varias lineas y la llamada sea más legible.

A continuación, el código para obtener los parámetros de cada proceso en el programa que inicia la única máquina virtual Java que se inicia.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Main {

    private static final String SEPARADOR = "sep";

    public static void main(String[] args) {
        List<String> params = new ArrayList<>();

        // Obtener los parámetros de cada "proceso"
        // Nota: Arrancar la máquina virtual consume mucho tiempo, en algunos casos
        // un tiempo considerable comparado con el programa, para evitar arrancar una JVM
        // por cada proceso pasar una lista de argumentos en una sola ejecución.
        List<String> actual = new ArrayList<>();
        for (String arg : args) {
            if (arg.equals(SEPARADOR)) {
                if (!actual.isEmpty()) {
                    params.add(actual);
                    actual = new ArrayList<>();
                }
                continue;
            }
            actual.add(arg);
	}

        if (!actual.isEmpty()) {
            params.add(actual);
        }

        // Procesar cada proceso con sus parámetros
        for (List<String> p : params) {
            procesar(o);
        }
    }
}
Main.java

El programa Java con el que he medido el tiempo de inicio de la JVM es el siguiente:

1
2
3
4
5
public class Test {
	public static void main(String[] args) {
		System.out.println("Executed");
	}
}
Test.java


Comparte el artículo: