Vraag Lijst met actieve JVM's op de lokale host


Hoe krijg ik in Java 6+ de lijst met draaiende JVM's op de localhost en hun specificaties (zoals Java-versie, threads, etc.)?

Biedt de Java API dergelijke functies? Is er een Java-bibliotheek die dit kan doen?


11
2018-03-04 23:07


oorsprong


antwoorden:


Je kunt gebruiken jps, een opdrachtregelprogramma dat wordt gedistribueerd met de jvm. Ik ken echter geen normale Java API. JConsole kan echter doen wat u vraagt, dus ik heb de bron bekeken. Het was best angstaanjagend, maar tijdens het rondkijken vond ik verwijzingen naar de jVisualVM-klassen, die ok zien als je Java 6+ specificeert. Dit is wat ik heb gevonden:

De klassen zijn allemaal in sun.tools, dus eerst moet je de jconsole.jar dat kwam met je JVM (veronderstelt natuurlijk Sun JVM) en voeg het toe aan je klassenpad. Dan kan een snel-n-vuile lijst van actieve VM's worden zoals:

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());
    }
}

Zodra u een verwijzing naar uw JVM's hebt, kunt u met hen communiceren via de API bijvoegen.


15
2018-03-04 23:12



jps in de \jdk\bin directory drukt een lijst met lopende Java-processen af, maar niet hun specificaties. Sommige bedrijfsomstandigheden zijn beschikbaar:

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

8
2018-03-04 23:11



U kunt een lijst met JVM's krijgen met behulp van de API bijvoegen, zonder gebruik te maken van jconsole.jar.

Het volgende toont aan dat de lijst met JVM's lokaal wordt uitgevoerd, sommige eigenschappen worden opgehaald, via JMX verbinding met elkaar maken en meer informatie via die verbinding wordt verkregen.

// ...

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) {
            // ...
        }
    }

Een lijst met beschikbare MXBeanzus hier. Meer over JMX in het algemeen is te vinden hier, die ik kreeg van een reactie op nog een antwoord op deze vraag. Sommige code hierboven kwam van beide links.

Notitie: Voor mij tenminste, ik moest toevoegen tools.jar naar het bootstrap-klassenpad om dit uit te voeren:

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

5
2018-01-30 01:30



Aanvullend op jps daar is de jstack tool, die het stacktracé van elk java-proces kan afdrukken. Het begin van de uitvoer bevat de VM-versie en vervolgens een lijst met threads met hun stacktraces.

Ik denk dat alle drie van jps, jstack en jconsole zijn geïmplementeerd op basis van de Java Management Beans API in javax.management.* en java.lang.management, dus kijk daar voor meer informatie over hoe u dit in uw eigen programma kunt doen.


Bewerken: hier is de documentatie-index voor de managementspullen. Vooral interessant lijkt het punt Monitoring en beheer met behulp van de JMX API.

(En ja, het werkt niet alleen voor de eigen VM, ook voor andere op hetzelfde systeem, en zelfs voor die op externe systemen als ze de juiste interface blootleggen.)


1
2018-03-04 23:21



Dit kwam ik vandaag te weten, is eigenlijk wat JPS doet: gewoon de map opsommen / Tmp / hsperfdata_foo / waar foo de gebruiker is die de JVM uitvoert.

Om een ​​onbekende reden worden de bestanden daar soms niet verwijderd wanneer een JVM wordt vermoord.

Hier zijn de links naar de broncode:

PerfDataFile.java

LocalVmManager


1
2017-10-19 14:43



Als je alleen maar een lijst van draaiende JVM's met PID's nodig hebt, werkt dit voor mij:

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());
        }
    }
}

Applicatie hoeft niet te worden uitgevoerd met speciale opdrachtregelparameters om op deze manier detecteerbaar te zijn. U hoeft JMX niet te activeren.

Niet alle JVM-apps spelen echter goed. Voor Eclipse zie ik alleen PID, maar geen klassenaam of opdrachtregel.

Je moet toevoegen tool.jar op uw klassenpad bevat het pakketten sun.jvmstat.*. De tool.jar is onderdeel van JDK. Bij een of andere variant van JDK / OS staat deze standaard op classpath, bij sommige moet je deze toevoegen. Dit doen met Maven afhankelijkheden is een beetje lastig, systemPath is vereist.

Als je meer wilt dan alleen lijst, check de link van Paŭlo Ebermann - Monitoring en beheer met behulp van de JMX API.

VirtualMachine vm = VirtualMachine.attach(pid);

Waar de PID uit de lijst komt. Voeg vervolgens uw agent toe aan (onvermoede) Java (of een andere JVM) -toepassing.

vm.loadAgent(agentJarLibraryFullPath);

Communiceer dan met uw agent via JMXConnector. Uw agent kan alle statistieken voor u verzamelen. Ik heb dat niet persoonlijk geprobeerd. U kunt zelfs de runtime-code op deze manier bewerken (wijzigen). Profilers gebruiken dat.


1
2018-06-11 16:35



Ik weet het niet van Java 6, maar ik denk dat je dit kunt doen door jconsole vanaf de opdrachtregel uit te voeren.

Ook als u op een * nix-platform bent, kunt u dit commando als volgt geven:

ps aux | grep java

Succes!


1
2018-03-04 23:14



Voor zover ik weet, biedt de jps de lijst met processen die zijn gestart met de jvm waartoe het behoort. Als je meerdere JDK's hebt geïnstalleerd, denk ik niet dat dit van nut zou kunnen zijn. Als u een lijst van alle Java-processen wilt hebben, moet u "ps -ef | grep java" gebruiken. Ik heb vaak gezien dat JVsualVM niet alle Java-processen kon identificeren die op een specifieke host draaiden. Als uw vereiste specifiek is voor een door JVM gelanceerd proces, zijn de bovenstaande suggesties van toepassing.


0
2018-03-05 01:21