| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
| * agreements. See the NOTICE file distributed with this work for additional information regarding |
| * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the License. You may obtain a |
| * copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software distributed under the License |
| * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| * or implied. See the License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package org.apache.geode.internal.stats50; |
| |
| import java.lang.management.ClassLoadingMXBean; |
| import java.lang.management.GarbageCollectorMXBean; |
| import java.lang.management.ManagementFactory; |
| import java.lang.management.MemoryMXBean; |
| import java.lang.management.MemoryPoolMXBean; |
| import java.lang.management.MemoryUsage; |
| import java.lang.management.OperatingSystemMXBean; |
| import java.lang.management.ThreadInfo; |
| import java.lang.management.ThreadMXBean; |
| import java.lang.reflect.Method; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.logging.log4j.Logger; |
| |
| import org.apache.geode.StatisticDescriptor; |
| import org.apache.geode.Statistics; |
| import org.apache.geode.StatisticsFactory; |
| import org.apache.geode.StatisticsType; |
| import org.apache.geode.StatisticsTypeFactory; |
| import org.apache.geode.SystemFailure; |
| import org.apache.geode.annotations.Immutable; |
| import org.apache.geode.annotations.internal.MakeNotStatic; |
| import org.apache.geode.distributed.internal.DistributionConfig; |
| import org.apache.geode.internal.ClassPathLoader; |
| import org.apache.geode.internal.statistics.StatisticsTypeFactoryImpl; |
| import org.apache.geode.internal.statistics.VMStatsContract; |
| import org.apache.geode.logging.internal.log4j.api.LogService; |
| |
| /** |
| * Statistics related to a Java VM. This version is hardcoded to use 1.5 MXBean stats from |
| * java.lang.management. |
| */ |
| public class VMStats50 implements VMStatsContract { |
| private static final Logger logger = LogService.getLogger(VMStats50.class.getName()); |
| |
| @Immutable |
| private static final StatisticsType vmType; |
| |
| @Immutable |
| private static final ClassLoadingMXBean clBean; |
| @Immutable |
| private static final MemoryMXBean memBean; |
| @Immutable |
| private static final OperatingSystemMXBean osBean; |
| /** |
| * This is actually an instance of UnixOperatingSystemMXBean but this class is not available on |
| * Windows so needed to make this a runtime check. |
| */ |
| @Immutable |
| private static final Object unixBean; |
| @Immutable |
| private static final Method getMaxFileDescriptorCount; |
| @Immutable |
| private static final Method getOpenFileDescriptorCount; |
| @Immutable |
| private static final Method getProcessCpuTime; |
| @Immutable |
| private static final ThreadMXBean threadBean; |
| |
| private static final int pendingFinalizationCountId; |
| private static final int loadedClassesId; |
| private static final int unloadedClassesId; |
| |
| private static final int daemonThreadsId; |
| private static final int peakThreadsId; |
| private static final int threadsId; |
| private static final int threadStartsId; |
| |
| private static final int cpusId; |
| private static final int freeMemoryId; |
| private static final int totalMemoryId; |
| private static final int maxMemoryId; |
| |
| @Immutable |
| private static final StatisticsType memoryUsageType; |
| private static final int mu_initMemoryId; |
| private static final int mu_maxMemoryId; |
| private static final int mu_usedMemoryId; |
| private static final int mu_committedMemoryId; |
| |
| @Immutable |
| private static final StatisticsType gcType; |
| private static final int gc_collectionsId; |
| private static final int gc_collectionTimeId; |
| @MakeNotStatic |
| private final Map<GarbageCollectorMXBean, Statistics> gcMap = |
| new HashMap<GarbageCollectorMXBean, Statistics>(); |
| |
| @Immutable |
| private static final StatisticsType mpType; |
| private static final int mp_l_initMemoryId; |
| private static final int mp_l_maxMemoryId; |
| private static final int mp_l_usedMemoryId; |
| private static final int mp_l_committedMemoryId; |
| // private static final int mp_gc_initMemoryId; |
| // private static final int mp_gc_maxMemoryId; |
| private static final int mp_gc_usedMemoryId; |
| // private static final int mp_gc_committedMemoryId; |
| private static final int mp_usageThresholdId; |
| private static final int mp_collectionUsageThresholdId; |
| private static final int mp_usageExceededId; |
| private static final int mp_collectionUsageExceededId; |
| @MakeNotStatic |
| private final Map<MemoryPoolMXBean, Statistics> mpMap = |
| new HashMap<MemoryPoolMXBean, Statistics>(); |
| |
| private static final int unix_fdLimitId; |
| private static final int unix_fdsOpenId; |
| private static final int processCpuTimeId; |
| |
| private long threadStartCount = 0; |
| private long[] allThreadIds = null; |
| private static final boolean THREAD_STATS_ENABLED = |
| Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "enableThreadStats"); |
| private final Map<Long, ThreadStatInfo> threadMap = |
| THREAD_STATS_ENABLED ? new HashMap<Long, ThreadStatInfo>() : null; |
| @Immutable |
| private static final StatisticsType threadType; |
| private static final int thread_blockedId; |
| private static final int thread_lockOwnerId; |
| private static final int thread_waitedId; |
| private static final int thread_inNativeId; |
| private static final int thread_suspendedId; |
| private static final int thread_blockedTimeId; |
| private static final int thread_waitedTimeId; |
| private static final int thread_cpuTimeId; |
| private static final int thread_userTimeId; |
| |
| static { |
| clBean = ManagementFactory.getClassLoadingMXBean(); |
| memBean = ManagementFactory.getMemoryMXBean(); |
| osBean = ManagementFactory.getOperatingSystemMXBean(); |
| { |
| Method m1 = null; |
| Method m2 = null; |
| Method m3 = null; |
| Object bean = null; |
| try { |
| Class c = |
| ClassPathLoader.getLatest().forName("com.sun.management.UnixOperatingSystemMXBean"); |
| if (c.isInstance(osBean)) { |
| m1 = c.getMethod("getMaxFileDescriptorCount", new Class[] {}); |
| m2 = c.getMethod("getOpenFileDescriptorCount", new Class[] {}); |
| bean = osBean; |
| } else { |
| // leave them null |
| } |
| // Always set ProcessCpuTime |
| m3 = osBean.getClass().getMethod("getProcessCpuTime", new Class[] {}); |
| if (m3 != null) { |
| m3.setAccessible(true); |
| } |
| } catch (VirtualMachineError err) { |
| SystemFailure.initiateFailure(err); |
| // If this ever returns, rethrow the error. We're poisoned |
| // now, so don't let this thread continue. |
| throw err; |
| } catch (Throwable ex) { |
| // Whenever you catch Error or Throwable, you must also |
| // catch VirtualMachineError (see above). However, there is |
| // _still_ a possibility that you are dealing with a cascading |
| // error condition, so you also need to check to see if the JVM |
| // is still usable: |
| logger.warn(ex.getMessage()); |
| SystemFailure.checkFailure(); |
| // must be on a platform that does not support unix mxbean |
| bean = null; |
| m1 = null; |
| m2 = null; |
| m3 = null; |
| } finally { |
| unixBean = bean; |
| getMaxFileDescriptorCount = m1; |
| getOpenFileDescriptorCount = m2; |
| getProcessCpuTime = m3; |
| } |
| } |
| threadBean = ManagementFactory.getThreadMXBean(); |
| if (THREAD_STATS_ENABLED) { |
| if (threadBean.isThreadCpuTimeSupported()) { |
| if (!threadBean.isThreadCpuTimeEnabled()) { |
| if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "enableCpuTime")) { |
| threadBean.setThreadCpuTimeEnabled(true); |
| } |
| } |
| } |
| if (threadBean.isThreadContentionMonitoringSupported()) { |
| if (!threadBean.isThreadContentionMonitoringEnabled()) { |
| if (Boolean.getBoolean(DistributionConfig.GEMFIRE_PREFIX + "enableContentionTime")) { |
| threadBean.setThreadContentionMonitoringEnabled(true); |
| } |
| } |
| } |
| } |
| StatisticsTypeFactory f = StatisticsTypeFactoryImpl.singleton(); |
| List<StatisticDescriptor> sds = new ArrayList<StatisticDescriptor>(); |
| sds.add(f.createIntGauge("pendingFinalization", |
| "Number of objects that are pending finalization in the java VM.", "objects")); |
| sds.add(f.createIntGauge("daemonThreads", "Current number of live daemon threads in this VM.", |
| "threads")); |
| sds.add(f.createIntGauge("threads", |
| "Current number of live threads (both daemon and non-daemon) in this VM.", "threads")); |
| sds.add( |
| f.createIntGauge("peakThreads", "High water mark of live threads in this VM.", "threads")); |
| sds.add(f.createLongCounter("threadStarts", |
| "Total number of times a thread has been started since this vm started.", "threads")); |
| sds.add(f.createIntGauge("cpus", "Number of cpus available to the java VM on its machine.", |
| "cpus", true)); |
| sds.add(f.createLongCounter("loadedClasses", "Total number of classes loaded since vm started.", |
| "classes")); |
| sds.add(f.createLongCounter("unloadedClasses", |
| "Total number of classes unloaded since vm started.", "classes", true)); |
| sds.add(f.createLongGauge("freeMemory", |
| "An approximation of the total amount of memory currently available for future allocated objects, measured in bytes.", |
| "bytes", true)); |
| sds.add(f.createLongGauge("totalMemory", |
| "The total amount of memory currently available for current and future objects, measured in bytes.", |
| "bytes")); |
| sds.add(f.createLongGauge("maxMemory", |
| "The maximum amount of memory that the VM will attempt to use, measured in bytes.", "bytes", |
| true)); |
| sds.add(f.createLongCounter("processCpuTime", "CPU timed used by the process in nanoseconds.", |
| "nanoseconds")); |
| if (unixBean != null) { |
| sds.add(f.createLongGauge("fdLimit", "Maximum number of file descriptors", "fds", true)); |
| sds.add(f.createLongGauge("fdsOpen", "Current number of open file descriptors", "fds")); |
| } |
| vmType = f.createType("VMStats", "Stats available on a 1.5 java virtual machine.", |
| sds.toArray(new StatisticDescriptor[0])); |
| pendingFinalizationCountId = vmType.nameToId("pendingFinalization"); |
| loadedClassesId = vmType.nameToId("loadedClasses"); |
| unloadedClassesId = vmType.nameToId("unloadedClasses"); |
| daemonThreadsId = vmType.nameToId("daemonThreads"); |
| peakThreadsId = vmType.nameToId("peakThreads"); |
| threadsId = vmType.nameToId("threads"); |
| threadStartsId = vmType.nameToId("threadStarts"); |
| cpusId = vmType.nameToId("cpus"); |
| freeMemoryId = vmType.nameToId("freeMemory"); |
| totalMemoryId = vmType.nameToId("totalMemory"); |
| maxMemoryId = vmType.nameToId("maxMemory"); |
| processCpuTimeId = vmType.nameToId("processCpuTime"); |
| if (unixBean != null) { |
| unix_fdLimitId = vmType.nameToId("fdLimit"); |
| unix_fdsOpenId = vmType.nameToId("fdsOpen"); |
| } else { |
| unix_fdLimitId = -1; |
| unix_fdsOpenId = -1; |
| } |
| |
| memoryUsageType = |
| f.createType("VMMemoryUsageStats", "Stats available on a 1.5 memory usage area", |
| new StatisticDescriptor[] {f.createLongGauge("initMemory", |
| "Initial memory the vm requested from the operating system for this area", "bytes"), |
| f.createLongGauge("maxMemory", |
| "The maximum amount of memory this area can have in bytes.", "bytes"), |
| f.createLongGauge("usedMemory", |
| "The amount of used memory for this area, measured in bytes.", "bytes"), |
| f.createLongGauge("committedMemory", |
| "The amount of committed memory for this area, measured in bytes.", "bytes")}); |
| mu_initMemoryId = memoryUsageType.nameToId("initMemory"); |
| mu_maxMemoryId = memoryUsageType.nameToId("maxMemory"); |
| mu_usedMemoryId = memoryUsageType.nameToId("usedMemory"); |
| mu_committedMemoryId = memoryUsageType.nameToId("committedMemory"); |
| |
| gcType = f.createType("VMGCStats", "Stats available on a 1.5 garbage collector", |
| new StatisticDescriptor[] { |
| f.createLongCounter("collections", |
| "Total number of collections this garbage collector has done.", "operations"), |
| f.createLongCounter("collectionTime", |
| "Approximate elapsed time spent doing collections by this garbage collector.", |
| "milliseconds"),}); |
| gc_collectionsId = gcType.nameToId("collections"); |
| gc_collectionTimeId = gcType.nameToId("collectionTime"); |
| |
| mpType = |
| f.createType("VMMemoryPoolStats", "Stats available on a 1.5 memory pool", |
| new StatisticDescriptor[] {f.createLongGauge("currentInitMemory", |
| "Initial memory the vm requested from the operating system for this pool", "bytes"), |
| f.createLongGauge("currentMaxMemory", |
| "The maximum amount of memory this pool can have in bytes.", "bytes"), |
| f.createLongGauge("currentUsedMemory", |
| "The estimated amount of used memory currently in use for this pool, measured in bytes.", |
| "bytes"), |
| f.createLongGauge("currentCommittedMemory", |
| "The amount of committed memory for this pool, measured in bytes.", "bytes"), |
| // f.createLongGauge("collectionInitMemory", |
| // "Initial memory the vm requested from the operating system for this pool", |
| // "bytes"), |
| // f.createLongGauge("collectionMaxMemory", |
| // "The maximum amount of memory this pool can have in bytes.", |
| // "bytes"), |
| f.createLongGauge("collectionUsedMemory", |
| "The estimated amount of used memory after that last garbage collection of this pool, measured in bytes.", |
| "bytes"), |
| // f.createLongGauge("collectionCommittedMemory", |
| // "The amount of committed memory for this pool, measured in bytes.", |
| // "bytes"), |
| f.createLongGauge("collectionUsageThreshold", |
| "The collection usage threshold for this pool in bytes", "bytes"), |
| f.createLongCounter("collectionUsageExceeded", |
| "Total number of times the garbage collector detected that memory usage in this pool exceeded the collectionUsageThreshold", |
| "exceptions"), |
| f.createLongGauge("usageThreshold", "The usage threshold for this pool in bytes", |
| "bytes"), |
| f.createLongCounter("usageExceeded", |
| "Total number of times that memory usage in this pool exceeded the usageThreshold", |
| "exceptions")}); |
| mp_l_initMemoryId = mpType.nameToId("currentInitMemory"); |
| mp_l_maxMemoryId = mpType.nameToId("currentMaxMemory"); |
| mp_l_usedMemoryId = mpType.nameToId("currentUsedMemory"); |
| mp_l_committedMemoryId = mpType.nameToId("currentCommittedMemory"); |
| // mp_gc_initMemoryId = mpType.nameToId("collectionInitMemory"); |
| // mp_gc_maxMemoryId = mpType.nameToId("collectionMaxMemory"); |
| mp_gc_usedMemoryId = mpType.nameToId("collectionUsedMemory"); |
| // mp_gc_committedMemoryId = mpType.nameToId("collectionCommittedMemory"); |
| mp_usageThresholdId = mpType.nameToId("usageThreshold"); |
| mp_collectionUsageThresholdId = mpType.nameToId("collectionUsageThreshold"); |
| mp_usageExceededId = mpType.nameToId("usageExceeded"); |
| mp_collectionUsageExceededId = mpType.nameToId("collectionUsageExceeded"); |
| |
| if (THREAD_STATS_ENABLED) { |
| threadType = f.createType("VMThreadStats", "Stats available on a 1.5 thread", |
| new StatisticDescriptor[] { |
| f.createLongCounter("blocked", |
| "Total number of times this thread blocked to enter or reenter a monitor", |
| "operations"), |
| f.createLongCounter("blockedTime", |
| "Total amount of elapsed time, approximately, that this thread has spent blocked to enter or reenter a monitor. May need to be enabled by setting -Dgemfire.enableContentionTime=true", |
| "milliseconds"), |
| f.createLongGauge("lockOwner", |
| "The thread id that owns the lock that this thread is blocking on.", "threadId"), |
| f.createIntGauge("inNative", "1 if the thread is in native code.", "boolean"), |
| f.createIntGauge("suspended", "1 if this thread is suspended", "boolean"), |
| f.createLongCounter("waited", |
| "Total number of times this thread waited for notification.", "operations"), |
| f.createLongCounter("waitedTime", |
| "Total amount of elapsed time, approximately, that this thread has spent waiting for notification. May need to be enabled by setting -Dgemfire.enableContentionTime=true", |
| "milliseconds"), |
| f.createLongCounter("cpuTime", |
| "Total cpu time for this thread. May need to be enabled by setting -Dgemfire.enableCpuTime=true.", |
| "nanoseconds"), |
| f.createLongCounter("userTime", |
| "Total user time for this thread. May need to be enabled by setting -Dgemfire.enableCpuTime=true.", |
| "nanoseconds"),}); |
| thread_blockedId = threadType.nameToId("blocked"); |
| thread_waitedId = threadType.nameToId("waited"); |
| thread_lockOwnerId = threadType.nameToId("lockOwner"); |
| thread_inNativeId = threadType.nameToId("inNative"); |
| thread_suspendedId = threadType.nameToId("suspended"); |
| thread_blockedTimeId = threadType.nameToId("blockedTime"); |
| thread_waitedTimeId = threadType.nameToId("waitedTime"); |
| thread_cpuTimeId = threadType.nameToId("cpuTime"); |
| thread_userTimeId = threadType.nameToId("userTime"); |
| } else { |
| threadType = null; |
| thread_blockedId = -1; |
| thread_waitedId = -1; |
| thread_lockOwnerId = -1; |
| thread_inNativeId = -1; |
| thread_suspendedId = -1; |
| thread_blockedTimeId = -1; |
| thread_waitedTimeId = -1; |
| thread_cpuTimeId = -1; |
| thread_userTimeId = -1; |
| } |
| } |
| |
| private final Statistics vmStats; |
| private final Statistics heapMemStats; |
| private final Statistics nonHeapMemStats; |
| |
| private final StatisticsFactory f; |
| private long id; |
| |
| public VMStats50(StatisticsFactory f, long id) { |
| this.f = f; |
| this.id = id; |
| this.vmStats = f.createStatistics(vmType, "vmStats", id); |
| this.heapMemStats = f.createStatistics(memoryUsageType, "vmHeapMemoryStats", id); |
| this.nonHeapMemStats = f.createStatistics(memoryUsageType, "vmNonHeapMemoryStats", id); |
| initMemoryPools(); // Fix for #40424 |
| initGC(); |
| } |
| |
| private boolean newThreadsStarted() { |
| long curStarts = threadBean.getTotalStartedThreadCount(); |
| return curStarts > this.threadStartCount; |
| } |
| |
| private void refreshThreads() { |
| if (!THREAD_STATS_ENABLED) { |
| return; |
| } |
| if (this.allThreadIds == null || newThreadsStarted()) { |
| this.allThreadIds = threadBean.getAllThreadIds(); |
| this.threadStartCount = threadBean.getTotalStartedThreadCount(); |
| } |
| ThreadInfo[] threadInfos = threadBean.getThreadInfo(this.allThreadIds, 0); |
| for (int i = 0; i < threadInfos.length; i++) { |
| long id = this.allThreadIds[i]; |
| ThreadInfo item = threadInfos[i]; |
| if (item != null) { |
| ThreadStatInfo tsi = threadMap.get(id); |
| if (tsi == null) { |
| threadMap.put(id, new ThreadStatInfo(item, this.f.createStatistics(threadType, |
| item.getThreadName() + '-' + item.getThreadId(), this.id))); |
| } else { |
| tsi.ti = item; |
| } |
| } else { |
| ThreadStatInfo tsi = threadMap.remove(id); |
| if (tsi != null) { |
| tsi.s.close(); |
| } |
| } |
| } |
| Iterator<Map.Entry<Long, ThreadStatInfo>> it = threadMap.entrySet().iterator(); |
| while (it.hasNext()) { |
| Map.Entry<Long, ThreadStatInfo> me = it.next(); |
| long id = me.getKey(); |
| ThreadStatInfo tsi = me.getValue(); |
| ThreadInfo ti = tsi.ti; |
| Statistics s = tsi.s; |
| s.setLong(thread_blockedId, ti.getBlockedCount()); |
| s.setLong(thread_lockOwnerId, ti.getLockOwnerId()); |
| s.setLong(thread_waitedId, ti.getWaitedCount()); |
| s.setInt(thread_inNativeId, ti.isInNative() ? 1 : 0); |
| s.setInt(thread_suspendedId, ti.isSuspended() ? 1 : 0); |
| if (threadBean.isThreadContentionMonitoringSupported() |
| && threadBean.isThreadContentionMonitoringEnabled()) { |
| s.setLong(thread_blockedTimeId, ti.getBlockedTime()); |
| s.setLong(thread_waitedTimeId, ti.getWaitedTime()); |
| } |
| if (threadBean.isThreadCpuTimeSupported() && threadBean.isThreadCpuTimeEnabled()) { |
| s.setLong(thread_cpuTimeId, threadBean.getThreadCpuTime(id)); |
| s.setLong(thread_userTimeId, threadBean.getThreadUserTime(id)); |
| } |
| } |
| } |
| |
| /** |
| * This set is used to workaround a JRockit bug 36348 in which getCollectionUsage throws |
| * OperationUnsupportedException instead of returning null. |
| */ |
| private final HashSet<String> collectionUsageUnsupported = new HashSet<String>(); |
| |
| /** |
| * Returns true if collection usage is not supported on the given bean. |
| */ |
| private boolean isCollectionUsageUnsupported(MemoryPoolMXBean mp) { |
| return this.collectionUsageUnsupported.contains(mp.getName()); |
| } |
| |
| /** |
| * Remember that the given bean does not support collection usage. |
| */ |
| private void setCollectionUsageUnsupported(MemoryPoolMXBean mp) { |
| this.collectionUsageUnsupported.add(mp.getName()); |
| } |
| |
| private void initMemoryPools() { |
| List<MemoryPoolMXBean> l = ManagementFactory.getMemoryPoolMXBeans(); |
| for (MemoryPoolMXBean item : l) { |
| if (item.isValid() && !mpMap.containsKey(item)) { |
| mpMap.put(item, |
| this.f.createStatistics(mpType, item.getName() + '-' + item.getType(), this.id)); |
| } |
| } |
| } |
| |
| private void refreshMemoryPools() { |
| boolean reInitPools = false; |
| Iterator<Map.Entry<MemoryPoolMXBean, Statistics>> it = mpMap.entrySet().iterator(); |
| while (it.hasNext()) { |
| Map.Entry<MemoryPoolMXBean, Statistics> me = it.next(); |
| MemoryPoolMXBean mp = me.getKey(); |
| Statistics s = me.getValue(); |
| if (!mp.isValid()) { |
| s.close(); |
| it.remove(); |
| reInitPools = true; |
| } else { |
| MemoryUsage mu = null; |
| try { |
| mu = mp.getUsage(); |
| } catch (IllegalArgumentException ex) { |
| // to workaround JRockit bug 36348 just ignore this and try the next pool |
| continue; |
| } catch (InternalError ie) { |
| // Somebody saw an InternalError once but I have no idea how to reproduce it. Was this a |
| // race between |
| // mp.isValid() and mp.getUsage()? Perhaps. |
| s.close(); |
| it.remove(); |
| reInitPools = true; |
| logger.warn("Accessing MemoryPool '{}' threw an Internal Error: {}", mp.getName(), |
| ie.getMessage()); |
| continue; |
| } |
| s.setLong(mp_l_initMemoryId, mu.getInit()); |
| s.setLong(mp_l_usedMemoryId, mu.getUsed()); |
| s.setLong(mp_l_committedMemoryId, mu.getCommitted()); |
| s.setLong(mp_l_maxMemoryId, mu.getMax()); |
| if (mp.isUsageThresholdSupported()) { |
| s.setLong(mp_usageThresholdId, mp.getUsageThreshold()); |
| s.setLong(mp_usageExceededId, mp.getUsageThresholdCount()); |
| } |
| mu = null; |
| if (!this.isCollectionUsageUnsupported(mp)) { |
| try { |
| mu = mp.getCollectionUsage(); |
| } catch (UnsupportedOperationException ex) { |
| // JRockit throws this exception instead of returning null |
| // as the javadocs say it should. See bug 36348 |
| this.setCollectionUsageUnsupported(mp); |
| } catch (IllegalArgumentException ex) { |
| // Yet another JRockit bug in which its code catches an assertion |
| // about the state of their bean stat values being inconsistent. |
| // See bug 36348. |
| this.setCollectionUsageUnsupported(mp); |
| } |
| } |
| if (mu != null) { |
| // s.setLong(mp_gc_initMemoryId, mu.getInit()); |
| s.setLong(mp_gc_usedMemoryId, mu.getUsed()); |
| // s.setLong(mp_gc_committedMemoryId, mu.getCommitted()); |
| // s.setLong(mp_gc_maxMemoryId, mu.getMax()); |
| if (mp.isCollectionUsageThresholdSupported()) { |
| s.setLong(mp_collectionUsageThresholdId, mp.getCollectionUsageThreshold()); |
| s.setLong(mp_collectionUsageExceededId, mp.getCollectionUsageThresholdCount()); |
| } |
| } |
| } |
| } |
| if (reInitPools) { |
| initMemoryPools(); |
| } |
| } |
| |
| private void initGC() { |
| List<GarbageCollectorMXBean> l = ManagementFactory.getGarbageCollectorMXBeans(); |
| for (GarbageCollectorMXBean item : l) { |
| if (item.isValid() && !gcMap.containsKey(item)) { |
| gcMap.put(item, this.f.createStatistics(gcType, item.getName(), this.id)); |
| } |
| } |
| } |
| |
| private void refreshGC() { |
| Iterator<Map.Entry<GarbageCollectorMXBean, Statistics>> it = gcMap.entrySet().iterator(); |
| while (it.hasNext()) { |
| Map.Entry<GarbageCollectorMXBean, Statistics> me = it.next(); |
| GarbageCollectorMXBean gc = me.getKey(); |
| Statistics s = me.getValue(); |
| if (!gc.isValid()) { |
| s.close(); |
| it.remove(); |
| } else { |
| s.setLong(gc_collectionsId, gc.getCollectionCount()); |
| s.setLong(gc_collectionTimeId, gc.getCollectionTime()); |
| } |
| } |
| } |
| |
| @Override |
| public void refresh() { |
| Runtime rt = Runtime.getRuntime(); |
| this.vmStats.setInt(pendingFinalizationCountId, memBean.getObjectPendingFinalizationCount()); |
| this.vmStats.setInt(cpusId, osBean.getAvailableProcessors()); |
| this.vmStats.setInt(threadsId, threadBean.getThreadCount()); |
| this.vmStats.setInt(daemonThreadsId, threadBean.getDaemonThreadCount()); |
| this.vmStats.setInt(peakThreadsId, threadBean.getPeakThreadCount()); |
| this.vmStats.setLong(threadStartsId, threadBean.getTotalStartedThreadCount()); |
| this.vmStats.setLong(loadedClassesId, clBean.getTotalLoadedClassCount()); |
| this.vmStats.setLong(unloadedClassesId, clBean.getUnloadedClassCount()); |
| this.vmStats.setLong(freeMemoryId, rt.freeMemory()); |
| this.vmStats.setLong(totalMemoryId, rt.totalMemory()); |
| this.vmStats.setLong(maxMemoryId, rt.maxMemory()); |
| |
| // Compute processCpuTime separately, if not accessible ignore |
| try { |
| if (getProcessCpuTime != null) { |
| Object v = getProcessCpuTime.invoke(osBean, new Object[] {}); |
| this.vmStats.setLong(processCpuTimeId, ((Long) v).longValue()); |
| } |
| } catch (VirtualMachineError err) { |
| SystemFailure.initiateFailure(err); |
| // If this ever returns, rethrow the error. We're poisoned |
| // now, so don't let this thread continue. |
| throw err; |
| } catch (Throwable ex) { |
| // Whenever you catch Error or Throwable, you must also |
| // catch VirtualMachineError (see above). However, there is |
| // _still_ a possibility that you are dealing with a cascading |
| // error condition, so you also need to check to see if the JVM |
| // is still usable: |
| SystemFailure.checkFailure(); |
| } |
| |
| if (unixBean != null) { |
| try { |
| Object v = getMaxFileDescriptorCount.invoke(unixBean, new Object[] {}); |
| this.vmStats.setLong(unix_fdLimitId, ((Long) v).longValue()); |
| v = getOpenFileDescriptorCount.invoke(unixBean, new Object[] {}); |
| this.vmStats.setLong(unix_fdsOpenId, ((Long) v).longValue()); |
| } catch (VirtualMachineError err) { |
| SystemFailure.initiateFailure(err); |
| // If this ever returns, rethrow the error. We're poisoned |
| // now, so don't let this thread continue. |
| throw err; |
| } catch (Throwable ex) { |
| // Whenever you catch Error or Throwable, you must also |
| // catch VirtualMachineError (see above). However, there is |
| // _still_ a possibility that you are dealing with a cascading |
| // error condition, so you also need to check to see if the JVM |
| // is still usable: |
| SystemFailure.checkFailure(); |
| } |
| } |
| |
| refresh(this.heapMemStats, getHeapMemoryUsage(memBean)); |
| refresh(this.nonHeapMemStats, getNonHeapMemoryUsage(memBean)); |
| refreshGC(); |
| refreshMemoryPools(); |
| refreshThreads(); |
| } |
| |
| /** |
| * Handle JDK-8207200 gracefully while fetching getHeapMemoryUsage from MemoryMXBean. |
| * |
| * @see <a href="https://bugs.openjdk.java.net/browse/JDK-8207200">JDK-8207200</a> |
| */ |
| private MemoryUsage getHeapMemoryUsage(MemoryMXBean memBean) { |
| try { |
| return memBean.getHeapMemoryUsage(); |
| } catch (IllegalArgumentException e) { |
| if (logger.isDebugEnabled()) { |
| logger.debug("JDK-8207200 prevented stat sampling for HeapMemoryUsage"); |
| } |
| return null; |
| } |
| } |
| |
| /** |
| * Handle JDK-8207200 gracefully while fetching getNonHeapMemoryUsage from MemoryMXBean. |
| * |
| * @see <a href="https://bugs.openjdk.java.net/browse/JDK-8207200">JDK-8207200</a> |
| */ |
| private MemoryUsage getNonHeapMemoryUsage(MemoryMXBean memBean) { |
| try { |
| return memBean.getNonHeapMemoryUsage(); |
| } catch (IllegalArgumentException e) { |
| if (logger.isDebugEnabled()) { |
| logger.debug("JDK-8207200 prevented stat sampling for NonHeapMemoryUsage"); |
| } |
| return null; |
| } |
| } |
| |
| private void refresh(Statistics stats, MemoryUsage mu) { |
| if (mu == null) { |
| return; |
| } |
| stats.setLong(mu_initMemoryId, mu.getInit()); |
| stats.setLong(mu_usedMemoryId, mu.getUsed()); |
| stats.setLong(mu_committedMemoryId, mu.getCommitted()); |
| stats.setLong(mu_maxMemoryId, mu.getMax()); |
| } |
| |
| @Override |
| public void close() { |
| this.heapMemStats.close(); |
| this.nonHeapMemStats.close(); |
| this.vmStats.close(); |
| closeStatsMap(this.mpMap); |
| closeStatsMap(this.gcMap); |
| } |
| |
| private void closeStatsMap(Map<?, Statistics> map) { |
| for (Statistics s : map.values()) { |
| s.close(); |
| } |
| } |
| |
| private static class ThreadStatInfo { |
| public ThreadInfo ti; |
| public final Statistics s; |
| |
| public ThreadStatInfo(ThreadInfo ti, Statistics s) { |
| this.ti = ti; |
| this.s = s; |
| } |
| } |
| |
| public static StatisticsType getType() { |
| return vmType; |
| } |
| |
| public Statistics getVMStats() { |
| return vmStats; |
| } |
| |
| public Statistics getVMHeapStats() { |
| return heapMemStats; |
| } |
| |
| public Statistics getVMNonHeapStats() { |
| return nonHeapMemStats; |
| } |
| |
| public static StatisticsType getGCType() { |
| return gcType; |
| } |
| |
| public static StatisticsType getMemoryPoolType() { |
| return mpType; |
| } |
| |
| public static StatisticsType getThreadType() { |
| return threadType; |
| } |
| |
| public static StatisticsType getMemoryUsageType() { |
| return memoryUsageType; |
| } |
| } |