Java ManagementFactory解析

作者: 一字马胡 | 来源:发表于2017-11-14 23:37 被阅读327次

    作者: 一字马胡
    转载标志 【2017-11-14】

    更新日志

    日期 更新内容 备注
    2017-11-14 新建文章 初版

    导入

    ManagementFactory是一个为我们提供各种获取JVM信息的工厂类,使用ManagementFactory可以获取大量的运行时JVM信息,比如JVM堆的使用情况,以及GC情况,线程信息等,通过这些数据项我们可以了解正在运行的JVM的情况,以便我们可以做出相应的调整。本文将基于ManagementFactory,介绍如何通过ManagementFactory获取一些运行时的JVM信息,下面首先展示了ManagementFactory的类图,可以看出它提供了大量的工厂方法,使得我们可以通过调用这些方法来获取运行时的相关Bean,通过这些Bean就可以获取到我们想要的数据:

    使用ManagementFactory

    上文中展示的ManagementFactory类图直观的说明了ManagementFactory提供的一些方法,可以看出我们可以获取的内容很多,下面将挑选几个具有代表性的MXBean来作为使用示例。

    线程:ThreadMXBean

    首先,可以通过下面的方式来获取一个ThreadMXBean:

    
    ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
    
    

    下面的图片展示了ThreadMXBean支持的查询方法:

    下面的代码展示了ThreadMXBean的使用方法,通过ThreadMXBean提供的方法,我们可以获取详细的运行时JVM内的线程信息:

    
        private static Map<String, Number> collectThreadInfo() {
            final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
            Map<String, Number> map = new LinkedHashMap<String, Number>();
            map.put("jvm.thread.count", threadBean.getThreadCount());
            map.put("jvm.thread.daemon.count", threadBean.getDaemonThreadCount());
            map.put("jvm.thread.totalstarted.count", threadBean.getTotalStartedThreadCount());
            ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadBean.getAllThreadIds());
    
            int newThreadCount = 0;
            int runnableThreadCount = 0;
            int blockedThreadCount = 0;
            int waitThreadCount = 0;
            int timeWaitThreadCount = 0;
            int terminatedThreadCount = 0;
    
            if (threadInfos != null) {
                for (ThreadInfo threadInfo : threadInfos) {
                    if (threadInfo != null) {
                        switch (threadInfo.getThreadState()) {
                            case NEW:
                                newThreadCount++;
                                break;
                            case RUNNABLE:
                                runnableThreadCount++;
                                break;
                            case BLOCKED:
                                blockedThreadCount++;
                                break;
                            case WAITING:
                                waitThreadCount++;
                                break;
                            case TIMED_WAITING:
                                timeWaitThreadCount++;
                                break;
                            case TERMINATED:
                                terminatedThreadCount++;
                                break;
                            default:
                                break;
                        }
                    } else {
                        /*
                         * If a thread of a given ID is not alive or does not exist,
                         * the corresponding element in the returned array will,
                         * contain null,because is mut exist ,so the thread is terminated
                         */
                        terminatedThreadCount++;
                    }
                }
            }
    
            map.put("jvm.thread.new.count", newThreadCount);
            map.put("jvm.thread.runnable.count", runnableThreadCount);
            map.put("jvm.thread.blocked.count", blockedThreadCount);
            map.put("jvm.thread.waiting.count", waitThreadCount);
            map.put("jvm.thread.time_waiting.count", timeWaitThreadCount);
            map.put("jvm.thread.terminated.count", terminatedThreadCount);
    
            long[] ids = threadBean.findDeadlockedThreads();
            map.put("jvm.thread.deadlock.count", ids == null ? 0 : ids.length);
    
            return map;
        }
    
    

    使用上面的代码可以获取当前JVM内的线程数量,并且可以计算出每种状态下的线程数量,更多数据可以参考上面展示的ThreadMXBean提供查询接口图。

    内存相关MxBean

    关于JVM内存相关的数据就比较丰富了,你可以参考文章浅谈JVM中的垃圾回收来初步了解JVM的内存模型,之后你应该也可以根据该文章了解到HotSpot JVM的实现中的内存模型,阅读完该文章之后,就应该知道年轻代、老年代、永久代等相关概念,下面的类是获取这些内存信息的根据类,其中包含了详细的JVM运行时内存信息,甚至包括了堆外内存信息。

    
    class MemoryInformation {
    
        // usedMemory 是heap使用内存 (eden+survivor+old)
        private final long m_usedMemory;
    
        // maxMemory 是heap最大内存
        private final long m_maxMemory;
    
        // usedOldGen "Old Gen"使用内存
        private final long m_usedOldGen;
    
        // maxOldGen "Old Gen"最大内存
        private final long m_maxOldGen;
    
        // usedPermGen "Perm Gen"使用内存
        private final long m_usedPermGen;
    
        // maxPermGen "Perm Gen"最大内存
        private final long m_maxPermGen;
    
        // usedEdenSpace "Eden Space"使用内存
        private final long m_usedEdenSpace;
    
        // maxEdenSpace "Eden Space"最大内存
        private final long m_maxEdenSpace;
    
        // usedSurvivorSpace "Survivor Space"使用内存
        private final long m_usedSurvivorSpace;
    
        // maxSurvivorSpace "Survivor Space"最大内存
        private final long m_maxSurvivorSpace;
    
        private final long m_usedNonHeapMemory;
    
        private final long m_maxNonHeapMemory;
    
        private MBeanServer m_mbeanServer = ManagementFactory.getPlatformMBeanServer();
    
        private static final String DIRECT_BUFFER_MBEAN = "java.nio:type=BufferPool,name=direct";
    
        private static final String MAPPED_BUFFER_MBEAN = "java.nio:type=BufferPool,name=mapped";
    
        public MemoryInformation() {
            m_usedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
            m_maxMemory = Runtime.getRuntime().maxMemory();
            final MemoryPoolMXBean permGenMemoryPool = getPermGenMemoryPool();
            if (permGenMemoryPool != null) {
                final MemoryUsage usage = permGenMemoryPool.getUsage();
                m_usedPermGen = usage.getUsed();
                m_maxPermGen = usage.getMax();
            } else {
                m_usedPermGen = 0;
                m_maxPermGen = 0;
            }
            final MemoryPoolMXBean oldGenMemoryPool = getOldGenMemoryPool();
            if (oldGenMemoryPool != null) {
                final MemoryUsage usage = oldGenMemoryPool.getUsage();
                m_usedOldGen = usage.getUsed();
                m_maxOldGen = usage.getMax();
            } else {
                m_usedOldGen = 0;
                m_maxOldGen = 0;
            }
    
            final MemoryPoolMXBean edenSpaceMemoryPool = getEdenSpacePool();
            if (edenSpaceMemoryPool != null) {
                final MemoryUsage usage = edenSpaceMemoryPool.getUsage();
                m_usedEdenSpace = usage.getUsed();
                m_maxEdenSpace = usage.getMax();
            } else {
                m_usedEdenSpace = 0;
                m_maxEdenSpace = 0;
            }
    
            final MemoryPoolMXBean survivorSpacePool = getSurvivorSpaceMemoryPool();
            if (survivorSpacePool != null) {
                final MemoryUsage usage = survivorSpacePool.getUsage();
                m_usedSurvivorSpace = usage.getUsed();
                m_maxSurvivorSpace = usage.getMax();
            } else {
                m_usedSurvivorSpace = 0;
                m_maxSurvivorSpace = 0;
            }
    
            final MemoryUsage nonHeapMemoryUsage = ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();
    
            m_usedNonHeapMemory = nonHeapMemoryUsage.getUsed();
            m_maxNonHeapMemory = nonHeapMemoryUsage.getMax();
        }
    
        public long getMaxEdenSpace() {
            return m_maxEdenSpace;
        }
    
        public long getMaxMemory() {
            return m_maxMemory;
        }
    
        public long getMaxNonHeapMemory() {
            return m_maxNonHeapMemory;
        }
    
        public long getMaxOldGen() {
            return m_maxOldGen;
        }
    
        public long getMaxPermGen() {
            return m_maxPermGen;
        }
    
        public long getMaxSurvivorSpace() {
            return m_maxSurvivorSpace;
        }
    
        private MemoryPoolMXBean getEdenSpacePool() {
            for (final MemoryPoolMXBean memoryPool : ManagementFactory.getMemoryPoolMXBeans()) {
                if (memoryPool.getName().endsWith("Eden Space")) {
                    return memoryPool;
                }
            }
            return null;
        }
    
        private MemoryPoolMXBean getOldGenMemoryPool() {
            for (final MemoryPoolMXBean memoryPool : ManagementFactory.getMemoryPoolMXBeans()) {
                if (memoryPool.getName().endsWith("Old Gen")) {
                    return memoryPool;
                }
            }
            return null;
        }
    
        private MemoryPoolMXBean getPermGenMemoryPool() {
            for (final MemoryPoolMXBean memoryPool : ManagementFactory.getMemoryPoolMXBeans()) {
                if (memoryPool.getName().endsWith("Perm Gen")) {
                    return memoryPool;
                }
            }
            return null;
        }
    
        private MemoryPoolMXBean getSurvivorSpaceMemoryPool() {
            for (final MemoryPoolMXBean memoryPool : ManagementFactory.getMemoryPoolMXBeans()) {
                if (memoryPool.getName().endsWith("Survivor Space")) {
                    return memoryPool;
                }
            }
            return null;
        }
    
        public long getUsedDirectBufferSize() {
            long directBufferSize = 0;
            try {
                ObjectName directPool = new ObjectName(DIRECT_BUFFER_MBEAN);
                directBufferSize = (Long) m_mbeanServer.getAttribute(directPool, "MemoryUsed");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return directBufferSize;
        }
    
        public long getUsedEdenSpace() {
            return m_usedEdenSpace;
        }
    
        public double getUsedEdenSpacePercentage() {
            if (m_usedEdenSpace > 0 && m_maxEdenSpace > 0) {
                return 100d * m_usedEdenSpace / m_maxEdenSpace;
            }
            return 0d;
        }
    
        public long getUsedMappedSize() {
            long mappedBufferSize = 0;
            try {
                ObjectName directPool = new ObjectName(MAPPED_BUFFER_MBEAN);
                mappedBufferSize = (Long) m_mbeanServer.getAttribute(directPool, "MemoryUsed");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return mappedBufferSize;
        }
    
        public long getUsedMemory() {
            return m_usedMemory;
        }
    
        public double getUsedMemoryPercentage() {
            return 100d * m_usedMemory / m_maxMemory;
        }
    
        public long getUsedNonHeapMemory() {
            return m_usedNonHeapMemory;
        }
    
        public double getUsedNonHeapPercentage() {
            if (m_usedNonHeapMemory > 0 && m_maxNonHeapMemory > 0) {
                return 100d * m_usedNonHeapMemory / m_maxNonHeapMemory;
            }
            return 0d;
        }
    
        public long getUsedOldGen() {
            return m_usedOldGen;
        }
    
        public double getUsedOldGenPercentage() {
            if (m_usedOldGen > 0 && m_maxOldGen > 0) {
                return 100d * m_usedOldGen / m_maxOldGen;
            }
            return 0d;
        }
    
        public long getUsedPermGen() {
            return m_usedPermGen;
        }
    
        public double getUsedPermGenPercentage() {
            if (m_usedPermGen > 0 && m_maxPermGen > 0) {
                return 100d * m_usedPermGen / m_maxPermGen;
            }
            return 0d;
        }
    
        public long getUsedSurvivorSpace() {
            return m_usedSurvivorSpace;
        }
    
        public double getUsedSurvivorSpacePercentage() {
            if (m_usedSurvivorSpace > 0 && m_maxSurvivorSpace > 0) {
                return 100d * m_usedSurvivorSpace / m_maxSurvivorSpace;
            }
            return 0d;
        }
    
        @Override
        public String toString() {
            return getClass().getSimpleName() + 
                    "[usedMemory=" + getUsedMemory() + 
                    ", maxMemory=" + getMaxMemory() + ']';
        }
    
    }
    
    

    虽然代码较多,但是都是可以直接运行的,参考价值非常大,如果在工作或者其他地方需要获取这些信息,可以直接参考就可以了。

    GC:GarbageCollectorMXBean

    同样,你应该首先阅读文章浅谈JVM中的垃圾回收来了解关于GC的一些基础内容,并且知道有哪些GC,以及设置参数,关于JVM的参数设置这部分内容,将会新建一个【JVM参数解析系列】,下面的代码可以获取关于JVM运行时GC相关的数据信息,在统计GC相关信息的时候使用了GarbageCollectorMXBean:

    
    
    class GarbageCollectorInfo {
        
        private long m_lastGcCount = 0;
    
        private long m_lastGcTime = 0;
    
        private long m_lastFullgcTime = 0;
    
        private long m_lastFullgcCount = 0;
    
        private long m_lastYounggcTime = 0;
    
        private long m_lastYounggcCount = 0;
        
        public long getM_lastGcCount() {
            return this.m_lastGcCount;
        }
        
        public long getM_lastGcTime() {
            return this.m_lastGcTime;
        }
        
        public long getM_lastFullgcTime() {
            return this.m_lastFullgcTime;
        }
        
        public long getM_lastFullgcCount() {
            return this.m_lastFullgcCount;
        }
        
        public long getM_lastYounggcTime() {
            return this.m_lastYounggcTime;
        }
        
        public long getM_lastYounggcCount() {
            return this.m_lastYounggcCount;
        }
    
        private Set<String> younggcAlgorithm = new LinkedHashSet<String>() {
            {
                add("Copy");
                add("ParNew");
                add("PS Scavenge");
                add("G1 Young Generation");
            }
        };
    
        private Set<String> oldgcAlgorithm = new LinkedHashSet<String>() {
            {
                add("MarkSweepCompact");
                add("PS MarkSweep");
                add("ConcurrentMarkSweep");
                add("G1 Old Generation");
            }
        };
    
        private Map<String, Number> collectGC() {
            long gcCount = 0;
            long gcTime = 0;
            long oldGCount = 0;
            long oldGcTime = 0;
            long youngGcCount = 0;
            long youngGcTime = 0;
            Map<String, Number> map = new LinkedHashMap<>();
    
            for (final GarbageCollectorMXBean garbageCollector : 
                    ManagementFactory.getGarbageCollectorMXBeans()) {
                
                gcTime += garbageCollector.getCollectionTime();
                gcCount += garbageCollector.getCollectionCount();
                String gcAlgorithm = garbageCollector.getName();
    
                if (younggcAlgorithm.contains(gcAlgorithm)) {
                    youngGcTime += garbageCollector.getCollectionTime();
                    youngGcCount += garbageCollector.getCollectionCount();
                } else if (oldgcAlgorithm.contains(gcAlgorithm)) {
                    oldGcTime += garbageCollector.getCollectionTime();
                    oldGCount += garbageCollector.getCollectionCount();
                } 
            }
            
            //
            //   GC实时统计信息
            //
            map.put("jvm.gc.count", gcCount - m_lastGcCount);
            map.put("jvm.gc.time", gcTime - m_lastGcTime);
            final long fullGcCount = oldGCount - m_lastFullgcCount;
            map.put("jvm.fullgc.count", fullGcCount);
            map.put("jvm.fullgc.time", oldGcTime - m_lastFullgcTime);
            map.put("jvm.younggc.count", youngGcCount - m_lastYounggcCount);
            map.put("jvm.younggc.time", youngGcTime - m_lastYounggcTime);
    
            if (youngGcCount > m_lastYounggcCount) {
                map.put("jvm.younggc.meantime", 
                        (youngGcTime - m_lastYounggcTime) / (youngGcCount - m_lastYounggcCount));
            } else {
                map.put("jvm.younggc.meantime", 0);
            }
    
            //
            //  GC增量统计信息
            //
            m_lastGcCount = gcCount;
            m_lastGcTime = gcTime;
            m_lastYounggcCount = youngGcCount;
            m_lastYounggcTime = youngGcTime;
            m_lastFullgcCount = oldGCount;
            m_lastFullgcTime = oldGcTime;
    
            return map;
        }
    }
    
    

    类加载器:ClassLoadingMXBean

    使用ClassLoadingMXBean可以获取当前JVM的类加载信息,下面的代码展示了ClassLoadingMXBean的使用方法:

    
        private static Map<String, Number> collectClassLoadingInfo() {
            ClassLoadingMXBean classLoadingMXBean = ManagementFactory.getClassLoadingMXBean();
            Map<String, Number> map = new LinkedHashMap<String, Number>();
    
            map.put("jvm.classloading.loaded.count", classLoadingMXBean.getLoadedClassCount());
            map.put("jvm.classloading.totalloaded.count", classLoadingMXBean.getTotalLoadedClassCount());
            map.put("jvm.classloading.unloaded.count", classLoadingMXBean.getUnloadedClassCount());
    
            return map;
        }
    
    

    结语

    本文包含了大量的代码,但是这些代码都是可执行的代码,执行这些代码可以快速直观的获取到JVM运行时的一些关键数据,根据这些数据我们就可以初步了解正在运行的JVM的一些信息,有时候就可以根据这些信息来优化我们的项目,比如是否有太多的线程在空闲状态,或者是否内存占用量很大,或者是否频繁发生Full GC(以此来调整我们的JVM启动参数)。这些数据对于维护和优化项目代码都是非常有价值的,本文试图分析与总结java的ManagementFactory的用法,从文章开篇的图片可以看出ManagementFactory提供了非常丰富的获取JVM运行时数据接口,而本文仅仅挑选了其中比较有代表性的MXBean,关于其他的MXBean的相关用法可以直接参考jdk源码,本文没有涉及到的那些MXBean将在未来合适的时候补充进来,或者在其他的文章中进行分析总结。

    相关文章

      网友评论

      本文标题:Java ManagementFactory解析

      本文链接:https://www.haomeiwen.com/subject/qumqvxtx.html