首页 > 其他分享 >JMX入门

JMX入门

时间:2023-06-03 14:34:34浏览次数:45  
标签:info JMX Java 入门 线程 MBean log

一、简介

Java管理扩展(JMX)技术是Java平台标准版(Java SE平台)的标准部分。JMX技术是在Java 2平台标准版(J2SE)5.0版本中添加到该平台的。JMX技术提供了一种简单、标准的管理资源(如应用程序、设备和服务)的方法。因为JMX技术是动态的,所以您可以在创建、安装和实现资源时使用它来监视和管理资源。您还可以使用JMX技术来监视和管理Java虚拟机(Java VM)。JMX规范用Java编程语言定义了用于管理和监控应用程序和网络的体系结构、设计模式、API和服务。使用JMX技术,给定的资源由一个或多个被称为ManagedBeans(MBean)的Java对象检测。这些MBean在核心托管对象服务器(称为MBean服务器)中注册。MBean服务器充当管理代理,可以在大多数已启用Java编程语言的设备上运行。规范定义了JMX代理,您可以使用这些代理来管理已正确配置用于管理的任何资源。JMX代理由一个MBean服务器和一组用于处理MBean的服务组成,MBean服务器中注册了MBean。通过这种方式,JMX代理直接控制资源,并使其可用于远程管理应用程序。对资源进行检测的方式完全独立于管理基础架构。因此,无论资源的管理应用程序是如何实现的,都可以使资源变得可管理。JMX技术定义了标准连接器(称为JMX连接器),使您能够从远程管理应用程序访问JMX代理。使用不同协议的JMX连接器提供相同的管理接口。因此,不管使用什么通信协议,管理应用程序都可以透明地管理资源。JMX代理也可以由不符合JMX规范的系统或应用程序使用,只要这些系统或应用支持JMX代理即可。

二、特点

  • JMX技术使Java应用程序能够在无需大量投资的情况下进行管理。

基于JMX技术的代理(JMX代理)可以在大多数支持Java技术的设备上运行。因此,Java应用程序可以变得易于管理,而对其设计几乎没有影响。Java应用程序只需要嵌入一个托管对象服务器,并使其某些功能作为在对象服务器中注册的一个或多个托管bean(MBean)可用。

  • JMX技术提供了管理Java应用程序、系统和网络的标准方法。

例如,Java Platform,Enterprise Edition(Java EE)5应用程序服务器符合JMX体系结构,因此可以使用JMX技术进行管理。

  • JMX技术可以用于Java虚拟机的开箱即用管理。

Java虚拟机(Java VM)是使用JMX技术进行高度检测的。您可以启动JMX代理来访问内置的Java虚拟机工具,从而远程监控和管理Java虚拟机。

  • JMX技术提供了一种可扩展的动态管理体系结构。

每个JMX代理服务都是一个独立的模块,可以根据需要插入到管理代理中。这种基于组件的方法意味着JMX解决方案可以从占地面积小的设备扩展到大型电信交换机及其他设备。JMX规范提供了一组核心代理服务。可以在管理基础设施中开发和动态加载、卸载或更新附加服务。

  • JMX技术利用了现有的标准Java技术。

只要需要,JMX规范就会引用现有的Java规范,例如Java命名和目录接口(J.N.D.I.)API。

  • 基于JMX技术的应用程序(JMX应用程序)可以从NetBeansIDE模块创建。

您可以从NetBeans更新中心获得一个模块(在NetBeans界面中选择Tools->Update Center),该模块使您能够使用NetBeans IDE创建JMX应用程序。这降低了JMX应用程序的开发成本。

  • JMX技术与现有的管理解决方案和新兴技术相集成。

JMXAPI是任何管理系统供应商都可以实现的开放接口。JMX解决方案可以使用查找和发现服务以及协议,例如Jini网络技术和服务定位协议(SLP)。

三、体系结构

 

Instrumentation

要使用JMX技术管理资源,必须首先用Java编程语言对资源进行检测。您使用称为MBean的Java对象来实现对资源的指令插入的访问。MBean必须遵循JMX规范中定义的设计模式和接口。这样做可以确保所有MBean以标准化的方式提供托管资源检测。除了标准MBean之外,JMX规范还定义了一种特殊类型的MBean,称为MXBean。MXBean是一个MBean,它只引用一组预定义的数据类型。一旦MBean对资源进行了检测,就可以通过JMX代理对其进行管理。MBean不需要知道它们将使用的JMX代理。MBean被设计为灵活、简单且易于实现。应用程序、系统和网络的开发人员可以以标准的方式使其产品易于管理,而无需了解或投资于复杂的管理系统。可以用最少的努力使现有资源易于管理。此外,JMX规范的插装级别提供了一种通知机制。此机制使MBean能够生成通知事件并将其传播到其他级别的组件。

JMX Agent

基于JMX技术的代理(JMX代理)是一种标准管理代理,它直接控制资源并使其可用于远程管理应用程序。JMX代理通常与它们控制的资源位于同一台机器上,但这种安排不是必需的。

JMX代理的核心组件是MBean服务器,这是一个注册MBean的托管对象服务器。JMX代理还包括一组用于管理MBean的服务,以及至少一个允许管理应用程序访问的通信适配器或连接器。当您实现JMX代理时,您不需要知道它将管理的资源的语义或功能。事实上,JMX代理甚至不需要知道它将为哪些资源提供服务,因为任何符合JMX规范的资源都可以使用任何提供资源所需服务的JMX代理。类似地,JMX代理不需要知道将访问它的管理应用程序的功能。

Remote Management

JMX技术工具可以通过多种不同的方式访问,既可以通过简单网络管理协议(SNMP)等现有管理协议,也可以通过专有协议。MBean服务器依赖于协议适配器和连接器,使JMX代理可以从代理的Java虚拟机(Java VM)之外的管理应用程序访问。

每个适配器通过在MBean服务器中注册的所有MBean的特定协议提供一个视图。例如,HTML适配器可以在浏览器中显示MBean。

连接器提供了一个管理器端接口,用于处理管理器和JMX代理之间的通信。每个连接器通过不同的协议提供相同的远程管理接口。当远程管理应用程序使用此接口时,它可以通过网络透明地连接到JMX代理,而不考虑协议。JMX技术提供了一个标准解决方案,用于将JMX技术工具导出到基于Java远程方法调用(Java RMI)的远程应用程序。

四、应用场景

1、dashboard监控面板

用于监测和管理JVM的常用资源,比如 JVM 内存、CPU 使用率、线程数、垃圾收集情况等等。

根据需要可以结合OSHI类库(基于JNA的本机操作系统和硬件信息库)一起使用;OSHI可以监控磁盘使用率、网络接口、计算机传感器等。

2、动态修改线上日志级别

以logback为例,只需在logback.xml配置文件中,增加单行配置即可启动JMX支持。

3、查看数据库连接池使用情况

4、查看自定义连接池使用情况

5、查看quartz-job任务执行情况

6、通知告警

JMX API定义了一种机制,使MBean能够生成通知,例如,通知状态更改、检测到的事件或问题。

五、MBean

MBean是一个托管Java对象,类似于JavaBeans组件,遵循JMX规范中提出的设计模式。MBean可以表示设备、应用程序或任何需要管理的资源。MBean公开了一个管理接口,该接口由以下内容组成:

  • 一组可读或可写的属性,或两者兼有。
  • 一组可调用的操作。
  • 自我描述。

MBean和MXBean的区别

1、MBean必须以MBean结尾,属性只能是基础类型和String。

2、MXBean是以MXBean结尾的public接口或者加了@MXBean,可以有自定义属性

 
JMX 中共有四种类型的 MBean,分别是 Standard MBean, Dynamic MBean, Open MBean, Model MBean。

类型 描述
Standard MBean 这种类型的MBean最简单,它能管理的资源(包括属性,方法,时间)必须定义在接口中,然后MBean必须实现这个接口。它的命名也必须遵循一定的规范,例如我们的MBean为Hello,则接口必须为HelloMBean。
Dynamic MBean 必须实现javax.management.DynamicMBean接口,所有的属性,方法都在运行时定义。Open MBean和Model MBean都属于Dynamic MBean。
Open MBean Open MBean 与其它动态 MBean 的唯一区别在于,前者对其公开接口的参数和返回值有所限制 —— 只能是基本类型或者 javax.management.openmbean包内的 ArrayType、CompositeType、TarbularType 等类型。这主要是考虑到管理系统的分布,很可能远端管理系统甚至 MBServer 层都不具有 MBean 接口中特殊的类。
Model MBean 与标准和动态MBean相比,你可以不用写MBean类,只需使用javax.management.modelmbean.RequiredModelMBean 即可。RequiredModelMBean实现了ModelMBean接口,而ModelMBean扩展了DynamicMBean接口,因此与DynamicMBean相似,Model MBean的管理资源也是在运行时定义的。与DynamicMBean不同的是,DynamicMBean管理的资源一般定义在DynamicMBean中(运行时才决定管理那些资源),而model MBean管理的资源并不在MBean中,而是在外部(通常是一个类),只有在运行时,才通过set方法将其加入到Model MBean中。

 

常用的MBean

1、OperatingSystemMXBean

运行Java虚拟机的操作系统的管理接口。可以通过调用ManagementFactory.getOperatingSystemMXBean方法或从平台MBeanServer方法获得。

@Test
public void test1() {
    OperatingSystemMXBean operatingSystemMXBean = ManagementFactory.getOperatingSystemMXBean();
    String name = operatingSystemMXBean.getName();
    log.info("操作系统名称:{}", name);

    String arch = operatingSystemMXBean.getArch();
    log.info("操作系统架构:{}", arch);

    double systemLoadAverage = operatingSystemMXBean.getSystemLoadAverage();
    log.info("最后一分钟的系统平均负载:{}", systemLoadAverage);

    int availableProcessors = operatingSystemMXBean.getAvailableProcessors();
    log.info("Java虚拟机可用的处理器数:{}", availableProcessors);

    String version = operatingSystemMXBean.getVersion();
    log.info("操作系统版本:{}", version);

    ObjectName objectName = operatingSystemMXBean.getObjectName();
    log.info("objectName:{}", objectName);
}

log是lombok注解。

2、RuntimeMXBean

Java虚拟机运行时系统的管理接口。可以通过调用ManagementFactory.getRuntimeMXBean方法或从平台MBeanServer方法获得。

@Test
public void test2() {
    RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
    String name = runtimeMXBean.getName();
    log.info("Java虚拟机名称:{}", name);

    boolean bootClassPathSupported = runtimeMXBean.isBootClassPathSupported();
    log.info("Java虚拟机是否支持引导类加载器用于搜索类文件的引导类路径机制:{}", bootClassPathSupported);

    if (bootClassPathSupported) {
        String bootClassPath = runtimeMXBean.getBootClassPath();
        log.info("引导类加载器路径:{}", bootClassPath);
    }

    String classPath = runtimeMXBean.getClassPath();
    log.info("系统类加载器路径:{}", classPath);

    List<String> inputArguments = runtimeMXBean.getInputArguments();

    log.info("传递给Java虚拟机的输入参数:{}", inputArguments);

    String libraryPath = runtimeMXBean.getLibraryPath();
    log.info("Java类库路径:{}", libraryPath);

    String managementSpecVersion = runtimeMXBean.getManagementSpecVersion();
    log.info("运行的Java虚拟机实现的管理接口的规范版本:{}", managementSpecVersion);

    long pid = runtimeMXBean.getPid();
    log.info("正在运行的Java虚拟机进程id:{}", pid);

    String specVendor = runtimeMXBean.getSpecVendor();
    log.info("Java虚拟机规范供应商:{}", specVendor);

    String specVersion = runtimeMXBean.getSpecVersion();
    log.info("Java虚拟机规范版本:{}", specVersion);

    long startTime = runtimeMXBean.getStartTime();
    log.info("Java虚拟机的启动时间:{}毫秒", startTime);

    Map<String, String> systemProperties = runtimeMXBean.getSystemProperties();
    log.info("系统属性开始");

    for (Map.Entry<String, String> entry : systemProperties.entrySet()) {
        log.info("\t\tkey:【{}】,value:【{}】", entry.getKey(), entry.getValue());
    }

    log.info("系统属性结束");

    long uptime = runtimeMXBean.getUptime();
    log.info("Java虚拟机的正常运行时间:{}毫秒", uptime);

    String vmName = runtimeMXBean.getVmName();
    log.info("Java虚拟机实现名称:{}", vmName);

    String vmVendor = runtimeMXBean.getVmVendor();
    log.info("Java虚拟机实现供应商:{}", vmVendor);

    String vmVersion = runtimeMXBean.getVmVersion();
    log.info("Java虚拟机版本:{}", vmVersion);

    ObjectName objectName = runtimeMXBean.getObjectName();
    log.info("objectName:{}", objectName);
}

3、MemoryMXBean

Java虚拟机内存系统的管理接口。可以通过调用ManagementFactory.getMemoryMXBean方法或从平台MBeanServer方法获得。

@Test
public void test3() {
    MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
    int objectPendingFinalizationCount = memoryMXBean.getObjectPendingFinalizationCount();
    log.info("待回收的对象的大致数量:{}", objectPendingFinalizationCount);

    log.info("堆使用情况");
    MemoryUsage heapMemoryUsage = memoryMXBean.getHeapMemoryUsage();
    long init = heapMemoryUsage.getInit();
    log.info("\tJava虚拟机最初从操作系统用于内存管理的内存量:{}字节", init);
    long used = heapMemoryUsage.getUsed();
    log.info("\t已使用:{}字节", used);
    long max = heapMemoryUsage.getMax();
    log.info("\t内存管理的最大内存量(-1表示没有限制):{}字节", max);
    long committed = heapMemoryUsage.getCommitted();
    log.info("\tJava虚拟机可以使用的最大内存量:{}字节", committed);

    log.info("\n");

    MemoryUsage nonHeapMemoryUsage = memoryMXBean.getNonHeapMemoryUsage();
    log.info("堆外使用情况");

    long init1 = nonHeapMemoryUsage.getInit();
    log.info("\tJava虚拟机最初从操作系统用于内存管理的内存量:{}字节", init1);
    long used1 = nonHeapMemoryUsage.getUsed();
    log.info("\t已使用:{}字节", used1);

    long max1 = nonHeapMemoryUsage.getMax();
    log.info("\t内存管理的最大内存量(-1表示没有限制):{}字节", max1);

    long committed1 = nonHeapMemoryUsage.getCommitted();
    log.info("\tJava虚拟机可以使用的最大内存量:{}字节", committed1);
}

4、ThreadMXBean

Java虚拟机的线程系统的管理接口。可以通过调用ManagementFactory.getThreadMXBean方法或从平台MBeanServer方法获得。

 @Test
public void test4() {
    Object obj = new Object();
    /**
     * 测试线程持有监视器情况
     */
    new Thread(() -> {
        synchronized (obj) {
            try {
                TimeUnit.SECONDS.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("测试线程:{}", Thread.currentThread().getName());
        }
    },"测试线程1")
            .start();

    try {
        TimeUnit.MICROSECONDS.sleep(200);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }

    new Thread(() -> {
        synchronized (obj) {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("测试线程:{}", Thread.currentThread().getName());
        }
    },"测试线程2")
            .start();

    Lock lock = new ReentrantLock();
    /**
     * 测试线程持有监视锁情况
     */
    new Thread(() -> {
        try {
            lock.lock();
            try {
                TimeUnit.SECONDS.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("测试线程:{}", Thread.currentThread().getName());
        } finally {
            lock.unlock();
        }
    },"测试线程3")
            .start();

    try {
        TimeUnit.MICROSECONDS.sleep(200);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }

    new Thread(() -> {
        try {
            lock.lock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("测试线程:{}", Thread.currentThread().getName());
        } finally {
            lock.unlock();
        }
    },"测试线程4")
            .start();

    Object A = new Object();
    Object B = new Object();
    /**
     * 测试线程持有监视器死锁情况
     */
    new Thread(() -> {
        synchronized (A) {
            try {
                TimeUnit.MICROSECONDS.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized (B) {
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log.info("测试线程:{}", Thread.currentThread().getName());
            }
        }
    },"测试线程5")
            .start();


    new Thread(() -> {
        synchronized (B) {
            try {
                TimeUnit.MICROSECONDS.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            synchronized (A) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log.info("测试线程:{}", Thread.currentThread().getName());
            }
        }
    },"测试线程6")
            .start();

    Lock lock1 = new ReentrantLock();
    Lock lock2 = new ReentrantLock();
    /**
     * 测试线程持有锁死锁情况
     */
    new Thread(() -> {
        try {
            lock1.lock();
            try {
                TimeUnit.MICROSECONDS.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            lock2.lock();
            try {
                TimeUnit.SECONDS.sleep(20);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("测试线程:{}", Thread.currentThread().getName());
        } finally {
            lock2.unlock();
            lock1.unlock();
        }
    },"测试线程7")
            .start();


    new Thread(() -> {
        try {
            lock2.lock();
            try {
                TimeUnit.MICROSECONDS.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            lock1.lock();
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            log.info("测试线程:{}", Thread.currentThread().getName());
        } finally {
            lock1.unlock();
            lock2.unlock();
        }
    },"测试线程8")
            .start();

    try {
        TimeUnit.SECONDS.sleep(4);
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }

    ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
    int threadCount = threadMXBean.getThreadCount();
    log.info("当前活动线程数,包括守护进程线程和非守护进程线程:{}", threadCount);

    long[] allThreadIds = threadMXBean.getAllThreadIds();

    for (long allThreadId : allThreadIds) {
        ThreadInfo threadInfo = threadMXBean.getThreadInfo(allThreadId);
        String threadName = threadInfo.getThreadName();
        //线程处于BLOCKED状态的次数。
        long blockedCount = threadInfo.getBlockedCount();
        //自上次启用线程争用监视以来,线程处于BLOCKED状态的总累积时间。如果禁用了线程争用监视,则此方法返回-1。
        long blockedTime = threadInfo.getBlockedTime();

        String lockName = threadInfo.getLockName();
        // 线程被阻塞的所锁所持有的线程id
        long lockOwnerId = threadInfo.getLockOwnerId();
        //线程被阻塞的所锁所持有的线程名称
        String lockOwnerName = threadInfo.getLockOwnerName();

        LockInfo lockInfo = threadInfo.getLockInfo();

        MonitorInfo[] lockedMonitors = threadInfo.getLockedMonitors();

        LockInfo[] lockedSynchronizers = threadInfo.getLockedSynchronizers();

        int priority = threadInfo.getPriority();
        //线程的StackTraceElement对象的数组。
        StackTraceElement[] stackTrace = threadInfo.getStackTrace();

        Thread.State threadState = threadInfo.getThreadState();
        //线程处于WAITING或TIMED_WAITING状态的次数
        long waitedCount = threadInfo.getWaitedCount();
        //自启用线程争用监视以来,线程处于WAITING或TIMED_WAITING状态的累计总时间。如果禁用了线程争用监视,则此方法返回-1。
        long waitedTime = threadInfo.getWaitedTime();

        log.info("线程id:{},线程名:{}", allThreadId, threadName);
        log.info("\t\t线程状态:{},线程处于BLOCKED状态的次数:{},自上次启用线程争用监视以来,线程处于BLOCKED状态的总累积时间(如果禁用了线程争用监视,则此方法返回-1):{},线程处于WAITING或TIMED_WAITING状态的次数:{},/自启用线程争用监视以来,线程处于WAITING或TIMED_WAITING状态的累计总时间(如果禁用了线程争用监视,则此方法返回-1):{}", threadState, blockedCount, blockedTime, waitedCount, waitedTime);
        log.info("\t\t线程等待的锁名:{},线程被阻塞的所锁所持有的线程id:{},线程被阻塞的所锁所持有的线程名称:{},线程被阻止等待的对象的className:{}", lockName, lockOwnerId, lockOwnerName, lockInfo != null ? lockInfo.getClassName() : null);
        log.info("\t\t线程持有的监视器对象:{}",printLockedMonitors(lockedMonitors));
        log.info("\t\t线程持有的同步器对象:{}", printLockedSynchronizers(lockedSynchronizers));
        log.info("\t\t线程的堆栈:{}", stackTrace);
    }

    log.info("\n");

    long currentThreadCpuTime = threadMXBean.getCurrentThreadCpuTime();
    log.info("当前线程的总CPU时间(以纳秒为单位):{}", currentThreadCpuTime);
    long currentThreadUserTime = threadMXBean.getCurrentThreadUserTime();
    log.info("当前线程在用户模式下的总CPU时间(以纳秒为单位):{}", currentThreadUserTime);
    int daemonThreadCount = threadMXBean.getDaemonThreadCount();
    log.info("当前运行的后台进程线程数:{}", daemonThreadCount);
    int peakThreadCount = threadMXBean.getPeakThreadCount();
    log.info("自Java虚拟机启动或峰值重置以来的峰值实时线程计数:{}", peakThreadCount);

    long[] deadlockedThreads = threadMXBean.findDeadlockedThreads();
    log.info("死锁的线程id数组:{}", deadlockedThreads);

    long[] monitorDeadlockedThreads = threadMXBean.findMonitorDeadlockedThreads();
    log.info("监视器死锁的线程id数组:{}", monitorDeadlockedThreads);
}


private String printLockedMonitors(MonitorInfo[] lockedMonitors) {
    if (lockedMonitors != null && lockedMonitors.length > 0) {
       return Arrays.stream(lockedMonitors).map(MonitorInfo::getClassName).collect(Collectors.joining());
    } else {
        return null;
    }
}

private String printLockedSynchronizers(LockInfo[] lockedSynchronizers) {
    if (lockedSynchronizers != null && lockedSynchronizers.length > 0) {
        return Arrays.stream(lockedSynchronizers).map(LockInfo::getClassName).collect(Collectors.joining());
    } else {
        return null;
    }
}

可以从控制台看到:
 


 

5、ClassLoadingMXBean

Java虚拟机的类加载系统的管理接口。可以通过调用ManagementFactory.getClassLoadingMXBean方法或从平台MBeanServer获得。

 @Test
public void test5() {
    ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
    int loadedClassCount = classLoadingMXBean.getLoadedClassCount();
    long unloadedClassCount = classLoadingMXBean.getUnloadedClassCount();
    long totalLoadedClassCount = classLoadingMXBean.getTotalLoadedClassCount();
    log.info("当前加载在Java虚拟机中的类的数:{},自Java虚拟机开始执行以来卸载的类的总数:{},自Java虚拟机开始执行以来已加载的类的总数:{}", loadedClassCount, unloadedClassCount, totalLoadedClassCount);
}

6、GarbageCollectorMXBean

Java虚拟机垃圾收集的管理接口。

@Test
public void test6() {
    List<GarbageCollectorMXBean> garbageCollectorMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
    for (GarbageCollectorMXBean garbageCollectorMXBean : garbageCollectorMXBeans) {
        // GC名称
        String name = garbageCollectorMXBean.getName();
        long collectionCount = garbageCollectorMXBean.getCollectionCount();
        long collectionTime = garbageCollectorMXBean.getCollectionTime();
        String[] memoryPoolNames = garbageCollectorMXBean.getMemoryPoolNames();
        log.info("名称:{},收集次数:{},收集耗时:{}毫秒,内存池名:{}", name, collectionCount, collectionTime, memoryPoolNames);
    }
}

可以查看使用的是哪种垃圾收集器,收集耗时,收集次数。

 
 
 
 
 

参考:https://blog.csdn.net/ory001/article/details/124760181

标签:info,JMX,Java,入门,线程,MBean,log
From: https://www.cnblogs.com/shigongp/p/17453336.html

相关文章

  • 【什么是CNN】入门学习随笔
    什么是CNN?https://www.bilibili.com/video/BV1zF411V7xu/?p=6&share_source=copy_web&vd_source=3a1ed9fe9b3eb506d95e8709e124a7ce CNN最基本的架构:卷积层、池化层、全连接层带参数计算才能算一层:卷积和全连接池化:一般选最大值转换:转换成向量感受野:下图为5*5......
  • 分布式医疗云平台(项目功能简介截图)【系统管理(科室管理、用户管理、角色管理、菜单管理
    项目功能截图1.系统管理 1.1.科室管理 1.2、用户管理1.3、角色管理 1.4、菜单管理  1.5、字典管理1.6、通知公告管理 1.7、登陆日志管理 1.8、操作日志管理 1.9、检查费用设置 1.10,挂号费用设置 项目功能截图1.系统管理 1.1.科室管理1.1.1、科室查询 1.1.2、科室添加......
  • Isito 入门:为什么学 Istio、Istio 是什么
    1,Istio概述......
  • Docker入门与实践
    Docker容器化技术对比虚拟机技术虚拟机技术虚拟出一套硬件资源,在此上安装操作系统进而运行一些软件而容器虚拟化出的容器都是直接使用宿主机硬件资源,基于宿主机的内核上进行运行,不用虚拟出来一套硬件资源,从而更快,更节约存储空间虚拟机与容器化1.两者是相辅相成的,可以共同使......
  • GAN的原理入门
    GAN的基本原理其实非常简单,这里以生成图片为例进行说明。假设我们有两个网络,G(Generator)和D(Discriminator)。正如它的名字所暗示的那样,它们的功能分别是:G是一个生成图片的网络,它接收一个随机的噪声z,通过这个噪声生成图片(如正态分布,auto-encoder是中间输出是一般也是),记做G(z)。D是一个......
  • ASP.NET Core MVC 从入门到精通之自动映射(一)
    随着技术的发展,ASP.NETCoreMVC也推出了好长时间,经过不断的版本更新迭代,已经越来越完善,本系列文章主要讲解ASP.NETCoreMVC开发B/S系统过程中所涉及到的相关内容,适用于初学者,在校毕业生,或其他想从事ASP.NETCoreMVC系统开发的人员。经过前几篇文章的讲解,初步了解ASP.NETCore......
  • AI入门(重实践)书籍推荐
    AI书籍推荐我最近看了下https://book.douban.com/subject/30147778/ 另外如果要看电子书的话建议看这个https://book.douban.com/subject/27154347/评价也非常高从项目着手机器学习和深度学习都有并且难度也不高其中文翻译电子版可以看这里https://github.com/it-ebooks......
  • Jasypt入门
    Jasypt是一个java库,它允许开发人员以最小的工作量为他/她的项目添加基本的加密功能,而不需要对密码学的工作原理有深入的了解。一、特性Jasypt为您提供了简单的单向(摘要)和双向加密技术。用于任何JCE提供程序的开放API,而不仅仅是默认的JavaVM提供程序。Jasypt可以很......
  • 一站式元数据治理平台——Datahub入门宝典
    随着数字化转型的工作推进,数据治理的工作已经被越来越多的公司提上了日程。作为新一代的元数据管理平台,Datahub在近一年的时间里发展迅猛,大有取代老牌元数据管理工具Atlas之势。国内Datahub的资料非常少,大部分公司想使用Datahub作为自己的元数据管理平台,但可参考的资料太少。所以整......
  • Angular Google Charts教程_编程入门自学教程_菜鸟教程-免费教程分享
    教程简介GoogleCharts是一个纯粹的基于JavaScript的图表库,旨在通过添加交互式图表功能来增强Web应用程序.它支持各种图表.在Chrome,Firefox,Safari,InternetExplorer(IE)等标准浏览器中使用SVG绘制图表.在传统的IE6中,VML用于绘制图形.AngularGoogleCharts是一个基于开源角度......