2011-03-04 27 views
11

¿Cómo obtener en Java 6+ la lista de JVM en ejecución en el host local y sus especificaciones (es decir, versión de Java, ejecución de hilos, etc.)?Lista de JVM en ejecución en el host local

¿La API de Java proporciona tales funciones? ¿Hay una biblioteca de Java que pueda hacer esto?

+1

VisualVM puede hacerlo así que debe haber una manera, aunque probablemente no es uno fácil . – biziclop

Respuesta

14

Puede utilizar jps, una herramienta de línea de comandos distribuido con la JVM. Sin embargo, no conozco ninguna API Java normal para ello. Sin embargo, JConsole puede hacer lo que usted pide, así que eché un vistazo a su fuente. Fue bastante aterrador, pero al mirar alrededor encontré referencias a las clases de jVisualVM, que están bien ya que se especifica Java 6+. Esto es lo que encontré:

Las clases están todos en sun.tools, por lo que en primer lugar hay que encontrar el jconsole.jar que vino con su máquina virtual Java (JVM de Sun asume, por supuesto) y agregarlo a la ruta de clases. A continuación, una lista rápida sucia-n-de las máquinas virtuales activas se puede conseguir como:

public static void main(final String[] args) { 
    final Map<Integer, LocalVirtualMachine> virtualMachines = LocalVirtualMachine.getAllVirtualMachines(); 
    for (final Entry<Integer, LocalVirtualMachine> entry : virtualMachines.entrySet()) { 
     System.out.println(entry.getKey() + " : " + entry.getValue().displayName()); 
    } 
} 

Una vez que tenga una referencia a sus máquinas virtuales de Java, puede comunicarse con ellos mediante el Attach API.

+0

¡Muy interesante! También acabo de encontrar esta solución http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html#gdhkz. Utiliza tools.jar en JAVA_HOME/lib (debe agregarlo en su classpath). – fsarradin

8

jps en el directorio \jdk\bin imprime una lista de procesos Java en ejecución pero no sus especificaciones. Algunas condiciones de funcionamiento están disponibles:

C:\Java\jdk1.6.0_23\bin>jps -mlv 
4660 -Dosgi.requiredJavaVersion=1.5 -Xms40m -Xmx512m -XX:MaxPermSize=256m 
6996 sun.tools.jps.Jps -mlv -Dapplication.home=C:\Java\jdk1.6.0_23 -Xms8m 
1

No sé acerca de Java 6, pero creo que se puede hacer ejecutando jconsole desde la línea de comandos.

Además, si usted está en una plataforma * nix puede emitir un comando como el siguiente:

ps aux | grep java 

Buena suerte!

+6

¿te refieres a '| grep java'? –

1

Además de jps existe la herramienta jstack, que puede imprimir el seguimiento de la pila de cualquier proceso de Java. El inicio de su salida contiene la versión VM, luego viene una lista de hilos con sus seguimientos de pila.

Creo que los tres de jps, jstack y jconsole se implementan en base a la API de Java Management Beans en javax.management.* y java.lang.management, así que busque más información sobre cómo hacer esto en su propio programa.


Editar: Aquí está el documentation index para la materia de gestión. Especialmente interesante parece el punto Monitoring and Management Using the JMX API.

(Y sí, funciona no sólo para la propia máquina virtual, también para otros en el mismo sistema, e incluso para los de sistemas remotos si se exponen a la interfaz correcta.)

+0

Creo que 'java.lang.management' contiene clases mientras que le permite inspeccionar la JVM en la que se está ejecutando actualmente, no otras que están en la misma computadora que usted. –

+0

¡Estoy corregido! Esto es bueno. –

+0

Gracias por los enlaces :) – fsarradin

0

Por lo que yo sé el jps proporciona la lista del proceso iniciado utilizando el jvm al que pertenece. Si tiene varios JDK instalados, no creo que sea de ayuda. Si quiere una lista de todos los procesos java, debe usar "ps -ef | grep java". He visto muchas veces que JVsualVM no pudo identificar todos los procesos de Java que se ejecutan en un host específico. Si su requerimiento es específico para un proceso JVM lanzado, se aplicarán las sugerencias anteriores.

1

Esto, me enteré hoy, es básicamente lo que hace JPS: simplemente liste la carpeta /tmp/hsperfdata_foo/ donde foo es el usuario que ejecuta la JVM.

Por algún motivo desconocido, a veces los archivos no se eliminarán cuando se mate una JVM.

Éstos son los enlaces en el código fuente:

PerfDataFile.java

LocalVmManager

1

Si necesita simplemente lista de funcionamiento JVM con los PID Esto funciona para mí:

package my.code.z025.util; 

import java.util.LinkedList; 
import java.util.List; 
import java.util.Set; 

import sun.jvmstat.monitor.HostIdentifier; 
import sun.jvmstat.monitor.MonitorException; 
import sun.jvmstat.monitor.MonitoredHost; 
import sun.jvmstat.monitor.MonitoredVm; 
import sun.jvmstat.monitor.MonitoredVmUtil; 
import sun.jvmstat.monitor.VmIdentifier; 

/** 
* Get list of all local active JVMs 
*/ 
public class ActiveJavaVirtualMachineExplorer { 

    /** 
    * Represents successfully captured active java virtual machine 
    */ 
    public static class ActiveVm { 
     private int pid; 
     private String name; 
      ... shortened ... 
    } 

    /** 
    * Represents unsuccessfully captured active java virtual machine, a failure. 
    * Keep cause exception. 
    */ 
    public static class FailedActiveVm extends ActiveVm { 
     private Exception cause; 
     ... shortened ... 
    } 

    /** 
    * Get list of all local active JVMs. 
    * <p> 
    * Returns something like: 
    * ActiveVm [pid=7992, name=my.code.z025.util.launch.RunHttpServer] 
    * ActiveVm [pid=6972, name=] 
    * ActiveVm [pid=8188, name=my.code.z025.util.launch.RunCodeServer] 
    * ActiveVm [pid=4532, name=org.eclipse.jdt.internal.junit.runner.RemoteTestRunner] 
    * The pid=6972 must be Eclipse. So this approach is not water tight. 
    */ 
    public static List<ActiveVm> getActiveLocalVms() { 
     List<ActiveVm> result = new LinkedList<ActiveVm>(); 
     MonitoredHost monitoredHost; 
     Set<Integer> activeVmPids; 
     try { 
      monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null)); 
      activeVmPids = monitoredHost.activeVms(); 
      for (Integer vmPid : activeVmPids) { 
       try { 
        MonitoredVm mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString())); 
        result.add(new ActiveVm(vmPid.intValue(), MonitoredVmUtil.mainClass(mvm, true))); 
        mvm.detach(); 
       } catch (Exception e) { 
        result.add(new FailedActiveVm(vmPid.intValue(), e)); 
       } 
      } 
      return result; 
     } catch (java.net.URISyntaxException e) { 
      throw new InternalError(e.getMessage()); 
     } catch (MonitorException e) { 
      throw new InternalError(e.getMessage()); 
     } 
    } 
} 

Aplicación no tiene que ejecutarse con ningún parámetro de línea de comando especial para ser detectable de esta manera. No es necesario activar JMX.

No todas las aplicaciones JVM funcionan bien. Para Eclipse veo solo PID, pero no nombre de clase o línea de comando.

Tiene que agregar tool.jar a su classpath, contiene los paquetes sun.jvmstat.*. El tool.jar es parte de JDK. Con alguna variante de JDK/OS está en classpath por defecto, con algunos tienes que agregarlo. Hacerlo con las dependencias de Maven es un poco complicado, se requiere systemPath.

Si quiere más de lo que acaba de enumerar, consulte el enlace de Paŭlo Ebermann - Monitoring and Management Using the JMX API.

VirtualMachine vm = VirtualMachine.attach(pid); 

Donde el PID se obtiene de la lista. Luego inserte su Agente en (insospechada) Java (o cualquier aplicación JVM).

vm.loadAgent(agentJarLibraryFullPath); 

Luego comuníquese con su agente a través de JMXConnector. Su agente puede recopilar todas las estadísticas para usted. Yo personalmente no lo he intentado. Incluso puede instrumentar (modificar) el código de tiempo de ejecución de esta manera. Los perfiladores usan eso.

4

En realidad, puede obtener una lista de JVM utilizando el Attach API, sin recurrir al uso de jconsole.jar.

A continuación se muestra cómo obtener la lista de JVM que se ejecutan localmente, cómo obtener algunas propiedades, cómo conectarse a través de JMX y cómo obtener más información a través de esa conexión.

// ... 

import com.sun.tools.attach.*; 
import javax.management.*; 

// ... 

    List<VirtualMachineDescriptor> descriptors = VirtualMachine.list(); 
    for (VirtualMachineDescriptor descriptor : descriptors) { 
     System.out.println("Found JVM: " + descriptor.displayName()); 
     try { 
      VirtualMachine vm = VirtualMachine.attach(descriptor); 
      String version = vm.getSystemProperties().getProperty("java.runtime.version"); 
      System.out.println(" Runtime Version: " + version); 

      String connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); 
      if (connectorAddress == null) { 
       vm.startLocalManagementAgent(); 
       connectorAddress = vm.getAgentProperties().getProperty("com.sun.management.jmxremote.localConnectorAddress"); 
      } 

      JMXServiceURL url = new JMXServiceURL(connectorAddress); 
      JMXConnector connector = JMXConnectorFactory.connect(url); 
      MBeanServerConnection mbs = connector.getMBeanServerConnection(); 

      ObjectName threadName = new ObjectName(ManagementFactory.THREAD_MXBEAN_NAME); 
      Integer threadCount = (Integer)mbs.getAttribute(threadName, "ThreadCount"); 
      System.out.println(" Thread count: " + threadCount); 
     } 
     catch (Exception e) { 
      // ... 
     } 
    } 

una lista de los disponibles MXBean s es here. Más sobre JMX en general se puede encontrar here, que obtuve de un comentario en another answer a esta pregunta. Algún código anterior provino de ambos enlaces.

Nota: Para mí, al menos, he tenido que añadir tools.jar a la ruta de clases de arranque para esto para ejecutar:

$ java -Xbootclasspath/a:${JAVA_HOME}/lib/tools.jar -jar <jar> 
+0

LocalVirtualMachine ya no está disponible en Java8, esta respuesta es ahora la correcta – loicmathieu

Cuestiones relacionadas