spring监控(九)-JVM内存监控
概述
共有加载类、运行时、线程池、内存池和内存回收几大类指标
加载类
指标定义类
@Data @NoArgsConstructor public class ClassLoadingMetric { private long loadedClasses; private long totalLoadedClasses; private long unloadedClasses; }
指标获取类
public class ClassLoadingProvider { private ClassLoadingMXBean mbean; public ClassLoadingProvider(){ this.mbean = ManagementFactory.getClassLoadingMXBean(); } public ClassLoadingMetric getClassLoadingMetrics(){ ClassLoadingMetric metrics = new ClassLoadingMetric(); metrics.setLoadedClasses(mbean.getLoadedClassCount()); metrics.setTotalLoadedClasses(mbean.getTotalLoadedClassCount()); metrics.setUnloadedClasses(mbean.getUnloadedClassCount()); return metrics; } }
运行时
指标定义类
@Data @NoArgsConstructor public class RuntimeMetric { private long startTimes; // JVM启动时间点 private long upTime; // JVM运行时间 private String specName;// Java虚拟机规范名称 private String specVersion;// Java虚拟机规范版本号 private String vmName;// Java虚拟机名称 private String vmVersion;// Java虚拟机版本号 }
指标获取类
public class RuntimeProvider { private RuntimeMXBean mbean; public RuntimeProvider(){ this.mbean = ManagementFactory.getRuntimeMXBean(); } public RuntimeMetric getClassLoadingMetrics(){ RuntimeMetric metrics = new RuntimeMetric(); metrics.setStartTimes(mbean.getStartTime()); metrics.setUpTime(mbean.getUptime()); metrics.setSpecName(mbean.getSpecName()); metrics.setSpecVersion(mbean.getSpecVersion()); metrics.setVmName(mbean.getVmName()); metrics.setVmVersion(mbean.getVmVersion()); return metrics; } }
线程池
指标定义类
@Data @NoArgsConstructor public class ThreadMetric { private long totalThreads; // 自JVM启动以来启动的所有线程数 private long livingThreads; // 当前activing的线程 private long peakThreads; // 线程数峰值 private long daemonThreads; // 守护线程数 }
指标获取类
public class ThreadProvider { private ThreadMXBean mbean; public ThreadProvider(){ this.mbean = ManagementFactory.getThreadMXBean(); } public ThreadMetric getClassLoadingMetrics(){ ThreadMetric metrics = new ThreadMetric(); metrics.setDaemonThreads(mbean.getDaemonThreadCount()); metrics.setPeakThreads(mbean.getPeakThreadCount()); metrics.setLivingThreads(mbean.getThreadCount()); metrics.setTotalThreads(mbean.getTotalStartedThreadCount()); return metrics; } }
内存池
JVM内存分为堆栈区和非堆栈区两个部分,这个是固定的。而对于内存池,有不同的实现,而不同的内存池其相应的指标名是不一样,因此应该区分获取。
JVM内存池指标定义
@Data @NoArgsConstructor public class JvmMemoryMetric { private long heapMax; private long heapUsed; private long heapAllocated; private long nonHeapMax; private long nonHeapUsed; private long nonHeapAllocated; private long permGenMax; private long permGenUsed; private long permGenAllocated; private long codeCacheMax; private long codeCacheUsed; private long codeCacheAllocated; private long edenMax; private long edenUsed; private long edenAllocated; private long oldMax; private long oldUsed; private long oldAllocated; private long survivorMax; private long survivorUsed; private long survivorAllocated; private long metaspaceMax; private long metaspaceUsed; private long metaspaceAllocated; }
内存池接口
public interface MemoryPoolMetricAccessor { void fetchMemoryPoolMetrics(JvmMemoryMetric memoryMetric); }
内存池基础类
public abstract class MemoryPoolModule implements MemoryPoolMetricAccessor { private MemoryPoolMXBean[] beans; public MemoryPoolModule(List<MemoryPoolMXBean> beans) { this.beans = beans.toArray(new MemoryPoolMXBean[0]); } @Override public void fetchMemoryPoolMetrics(JvmMemoryMetric memoryMetric) { // 循环每个内存区域,收集每个 MemoryPool 指标 for (MemoryPoolMXBean bean : beans) { String name = bean.getName(); MemoryUsage usage = bean.getUsage(); // 获得内存区域类型 if (contains(getCodeCacheNames(), name)) { memoryMetric.setCodeCacheMax(usage.getMax()); memoryMetric.setCodeCacheUsed(usage.getUsed()); memoryMetric.setCodeCacheAllocated(usage.getCommitted()); } else if (contains(getEdenNames(), name)) { memoryMetric.setEdenMax(usage.getMax()); memoryMetric.setEdenUsed(usage.getUsed()); memoryMetric.setEdenAllocated(usage.getCommitted()); } else if (contains(getOldNames(), name)) { memoryMetric.setOldMax(usage.getMax()); memoryMetric.setOldUsed(usage.getUsed()); memoryMetric.setOldAllocated(usage.getCommitted()); } else if (contains(getSurvivorNames(), name)) { memoryMetric.setSurvivorMax(usage.getMax()); memoryMetric.setSurvivorUsed(usage.getUsed()); memoryMetric.setSurvivorAllocated(usage.getCommitted()); } else if (contains(getMetaspaceNames(), name)) { memoryMetric.setMetaspaceMax(usage.getMax()); memoryMetric.setMetaspaceUsed(usage.getUsed()); memoryMetric.setMetaspaceAllocated(usage.getCommitted()); } else if (contains(getPermNames(), name)) { memoryMetric.setPermGenMax(usage.getMax()); memoryMetric.setPermGenUsed(usage.getUsed()); memoryMetric.setPermGenAllocated(usage.getCommitted()); } else { continue; } } } private boolean contains(String[] possibleNames, String name) { for (String possibleName : possibleNames) { if (name.equals(possibleName)) { return true; } } return false; } protected abstract String[] getPermNames(); protected abstract String[] getCodeCacheNames(); protected abstract String[] getEdenNames(); protected abstract String[] getOldNames(); protected abstract String[] getSurvivorNames(); protected abstract String[] getMetaspaceNames(); }
CMSCollector内存池类
public class CMSCollectorModule extends MemoryPoolModule { public CMSCollectorModule(List<MemoryPoolMXBean> beans) { super(beans); } @Override protected String[] getPermNames() { return new String[] {"CMS Perm Gen", "Compressed Class Space"}; } @Override protected String[] getCodeCacheNames() { return new String[] {"Code Cache"}; } @Override protected String[] getEdenNames() { return new String[] {"Par Eden Space"}; } @Override protected String[] getOldNames() { return new String[] {"CMS Old Gen"}; } @Override protected String[] getSurvivorNames() { return new String[] {"Par Survivor Space"}; } @Override protected String[] getMetaspaceNames() { return new String[] {"Metaspace"}; } }
G1内存池类
public class G1CollectorModule extends MemoryPoolModule { public G1CollectorModule(List<MemoryPoolMXBean> beans) { super(beans); } @Override protected String[] getPermNames() { return new String[] {"G1 Perm Gen", "Compressed Class Space"}; } @Override protected String[] getCodeCacheNames() { return new String[] {"Code Cache"}; } @Override protected String[] getEdenNames() { return new String[] {"G1 Eden Space"}; } @Override protected String[] getOldNames() { return new String[] {"G1 Old Gen"}; } @Override protected String[] getSurvivorNames() { return new String[] {"G1 Survivor Space"}; } @Override protected String[] getMetaspaceNames() { return new String[] {"Metaspace"}; } }
Parallel内存池类
public class ParallelCollectorModule extends MemoryPoolModule { public ParallelCollectorModule(List<MemoryPoolMXBean> beans) { super(beans); } @Override protected String[] getPermNames() { return new String[] {"PS Perm Gen", "Compressed Class Space"}; } @Override protected String[] getCodeCacheNames() { return new String[] {"Code Cache"}; } @Override protected String[] getEdenNames() { return new String[] {"PS Eden Space"}; } @Override protected String[] getOldNames() { return new String[] {"PS Old Gen"}; } @Override protected String[] getSurvivorNames() { return new String[] {"PS Survivor Space"}; } @Override protected String[] getMetaspaceNames() { return new String[] {"Metaspace"}; } }
SerialCollector类
public class SerialCollectorModule extends MemoryPoolModule { public SerialCollectorModule(List<MemoryPoolMXBean> beans) { super(beans); } @Override protected String[] getPermNames() { return new String[] {"Perm Gen", "Compressed Class Space"}; } @Override protected String[] getCodeCacheNames() { return new String[] {"Code Cache"}; } @Override protected String[] getEdenNames() { return new String[] {"Eden Space"}; } @Override protected String[] getOldNames() { return new String[] {"Tenured Gen"}; } @Override protected String[] getSurvivorNames() { return new String[] {"Survivor Space"}; } @Override protected String[] getMetaspaceNames() { return new String[] {"Metaspace"}; } }
内存池指标获取类
public class MemoryPoolProvider { private MemoryPoolMetricAccessor metricAccessor; private List<MemoryPoolMXBean> beans; public MemoryPoolProvider() { // 创建 JVM GC 方式对应的 MemoryPoolMetricAccessor对象 beans = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean bean : beans) { String name = bean.getName(); MemoryPoolMetricAccessor accessor = findByBeanName(name); if (accessor != null) { metricAccessor = accessor; break; } } if (metricAccessor == null) { metricAccessor = new UnknownMemoryPool(); } } public void fetchMemoryPoolMetrics(JvmMemoryMetric memoryMetric) { metricAccessor.fetchMemoryPoolMetrics(memoryMetric); } private MemoryPoolMetricAccessor findByBeanName(String name) { if (name.indexOf("PS") > -1) { // ParallelCollector //Parallel (Old) collector ( -XX:+UseParallelOldGC ) return new ParallelCollectorModule(beans); } else if (name.indexOf("CMS") > -1) { // CMSCollector // CMS collector ( -XX:+UseConcMarkSweepGC ) return new CMSCollectorModule(beans); } else if (name.indexOf("G1") > -1) { // G1Collector // G1 collector ( -XX:+UseG1GC ) return new G1CollectorModule(beans); } else if ("Survivor Space".equals(name)) { // SerialCollector // Serial collector ( -XX:+UseSerialGC ) return new SerialCollectorModule(beans); } else { // Unknown return null; } } }
内存回收
指标定义类
@Data @NoArgsConstructor public class GCMetric { private long fullGCCount; private long fullGCTime; private long minorGCCount; private long minorGCTime; }
指标获取接口
public interface GCMetricAccessor { GCMetric getGCMetrics(); }
指标获取基类
public abstract class GCModule implements GCMetricAccessor { private GarbageCollectorMXBean[] beans; private volatile long lastMinorGCCount; private volatile long lastMinorGCTime; private volatile long lastFullGCCount; private volatile long lastFullGCTime; public GCModule(List<GarbageCollectorMXBean> beans) { this.beans = beans.toArray(new GarbageCollectorMXBean[0]); } @Override public GCMetric getGCMetrics() { GCMetric metrics = new GCMetric(); for (GarbageCollectorMXBean bean : beans) { // 获得 String name = bean.getName(); if (name.equals(getNewGCName())) { long minorGCCount = bean.getCollectionCount(); long minorGCTime = bean.getCollectionTime(); metrics.setMinorGCCount(minorGCCount - this.lastMinorGCCount); metrics.setMinorGCTime(minorGCTime - this.lastMinorGCTime); this.lastMinorGCCount = minorGCCount; this.lastMinorGCTime = minorGCTime; } else if (name.equals(getOldGCName())) { long fullGCCount = bean.getCollectionCount(); long fullGCTime = bean.getCollectionTime(); metrics.setFullGCCount(fullGCCount - this.lastFullGCCount); metrics.setFullGCTime(fullGCTime - this.lastFullGCTime); this.lastFullGCCount = fullGCCount; this.lastFullGCTime = fullGCTime; } else { continue; } } return metrics; } protected abstract String getOldGCName(); protected abstract String getNewGCName(); }
CMSGCModule类
public class CMSGCModule extends GCModule { public CMSGCModule(List<GarbageCollectorMXBean> beans) { super(beans); } @Override protected String getOldGCName() { return "ConcurrentMarkSweep"; } @Override protected String getNewGCName() { return "ParNew"; } }
G1GCModule
public class G1GCModule extends GCModule { public G1GCModule(List<GarbageCollectorMXBean> beans) { super(beans); } @Override protected String getOldGCName() { return "G1 Old Generation"; } @Override protected String getNewGCName() { return "G1 Young Generation"; } }
ParallelGCModule
public class ParallelGCModule extends GCModule { public ParallelGCModule(List<GarbageCollectorMXBean> beans) { super(beans); } @Override protected String getOldGCName() { return "PS MarkSweep"; } @Override protected String getNewGCName() { return "PS Scavenge"; } }
SerialGCModule
public class SerialGCModule extends GCModule { public SerialGCModule(List<GarbageCollectorMXBean> beans) { super(beans); } @Override protected String getOldGCName() { return "MarkSweepCompact"; } @Override protected String getNewGCName() { return "Copy"; } }
UnknowGC
public class UnknowGC implements GCMetricAccessor { @Override public GCMetric getGCMetrics() { return new GCMetric(); } }
指标获取类
public class GCProvider { private GCMetricAccessor metricAccessor; private List<GarbageCollectorMXBean> beans; public GCProvider() { // 获得 GarbageCollectorMXBean 数组。 beans = ManagementFactory.getGarbageCollectorMXBeans(); // 找到 GC 算法,创建对应的 GCMetricAccessor 对象。 for (GarbageCollectorMXBean bean : beans) { String name = bean.getName(); GCMetricAccessor accessor = findByBeanName(name); if (accessor != null) { metricAccessor = accessor; break; } } // 找不到 GC 算法,创建 UnknowGC 对象。 if (metricAccessor == null) { this.metricAccessor = new UnknowGC(); } } public GCMetric getGCMetrics() { return metricAccessor.getGCMetrics(); } private GCMetricAccessor findByBeanName(String name) { if (name.indexOf("PS") > -1) { //Parallel (Old) collector ( -XX:+UseParallelOldGC ) return new ParallelGCModule(beans); } else if (name.indexOf("ConcurrentMarkSweep") > -1) { // CMS collector ( -XX:+UseConcMarkSweepGC ) return new CMSGCModule(beans); } else if (name.indexOf("G1") > -1) { // G1 collector ( -XX:+UseG1GC ) return new G1GCModule(beans); } else if ("MarkSweepCompact".equals(name)) { // Serial collector ( -XX:+UseSerialGC ) return new SerialGCModule(beans); } else { // Unknown return null; } } }
各种指标获取类
@NoArgsConstructor public class JvmMetricsFetcher { private Logger logger = LoggerFactory.getLogger(getClass()); private static final String METRIC_NAME_APP_INSTANCE_JVM_MEM = "jvm-mem"; private static final String METRIC_NAME_APP_INSTANCE_JVM_GC = "jvm-gc"; private static final String METRIC_FIELD_NAME_FULLGCCOUNT = "fullGCCount"; private static final String METRIC_FIELD_NAME_FULLGCTIME = "fullGCTime"; private static final String METRIC_FIELD_NAME_MINORGCCOUNT = "minorGCCount"; private static final String METRIC_FIELD_NAME_MINORGCTIME = "minorGCTime"; private static final String METRIC_FIELD_NAME_HEAPMAX = "heapMax"; private static final String METRIC_FIELD_NAME_HEAPUSED = "heapUsed"; private static final String METRIC_FIELD_NAME_HEAPALLOCATED = "heapAllocated"; private static final String METRIC_FIELD_NAME_NONHEAPMAX = "nonHeapMax"; private static final String METRIC_FIELD_NAME_NONHEAPUSED = "nonHeapUsed"; private static final String METRIC_FIELD_NAME_NONHEAPALLOCATED = "nonHeapAllocated"; private static final String METRIC_FIELD_NAME_PERMGENMAX = "permGenMax"; private static final String METRIC_FIELD_NAME_PERMGENUSED = "permGenUsed"; private static final String METRIC_FIELD_NAME_PERMGENALLOCATED = "permGenAllocated"; private static final String METRIC_FIELD_NAME_CODECACHEMAX = "codeCacheMax"; private static final String METRIC_FIELD_NAME_CODECACHEUSED = "codeCacheUsed"; private static final String METRIC_FIELD_NAME_CODECACHEALLOCATED = "codeCacheAllocated"; private static final String METRIC_FIELD_NAME_EDENMAX = "edenMax"; private static final String METRIC_FIELD_NAME_EDENUSED = "edenUsed"; private static final String METRIC_FIELD_NAME_EDENALLOCATED = "edenAllocated"; private static final String METRIC_FIELD_NAME_OLDMAX = "oldMax"; private static final String METRIC_FIELD_NAME_OLDUSED = "oldUsed"; private static final String METRIC_FIELD_NAME_OLDALLOCATED = "oldAllocated"; private static final String METRIC_FIELD_NAME_SURVIVORMAX = "survivorMax"; private static final String METRIC_FIELD_NAME_SURVIVORUSED = "survivorUsed"; private static final String METRIC_FIELD_NAME_SURVIVORALLOCATED = "survivorAllocated"; private static final String METRIC_FIELD_NAME_METASPACEMAX = "metaspaceMax"; private static final String METRIC_FIELD_NAME_METASPACEUSED = "metaspaceUsed"; private static final String METRIC_FIELD_NAME_METASPACEALLOCATED = "metaspaceAllocated"; private static final String METRIC_FIELD_NAME_LOADEDCLASSES = "loadedClasses"; private static final String METRIC_FIELD_NAME_TOTALLOADEDCLASSES = "totalLoadedClasses"; private static final String METRIC_FIELD_NAME_UNLOADEDCLASSES = "unloadedClasses"; private static final String METRIC_FIELD_NAME_TOTALTHREADS = "totalThreads"; private static final String METRIC_FIELD_NAME_LIVINGTHREADS = "livingThreads"; private static final String METRIC_FIELD_NAME_PEAKTHREADS = "peakThreads"; private static final String METRIC_FIELD_NAME_DAEMONTHREAD = "daemonThread"; @Value("${wdgm.monitor.jvm.metrics.fetch.intervalMS:5000}") private int fetchingExecutingInterval; @Value("${wdgm.monitor.jvm.metrics.output.intervalMS:10000}") private int outputingExecutingInterval; @Autowired private IMonitorDataOutputer metricOutputer; @Autowired private ClassLoadingProvider classLoadingProvider; @Autowired private GCProvider gcProvider; @Autowired private MemoryProvider memoryProvider; @Autowired private ThreadProvider threadProvider; private Queue<MonitorDataItem> metricCache; private Queue<MonitorDataItem> metricCacheBck; private Lock cacheOpLock = new ReentrantLock(); private ScheduledExecutorService executorForFetching; private ScheduledExecutorService executorForOutputing; @PostConstruct public void init(){ this.metricCache = new LinkedBlockingDeque<>(); this.metricCacheBck = new LinkedBlockingDeque<>(); // 启动线程 this.executorForFetching = Executors.newScheduledThreadPool(1); this.executorForOutputing = Executors.newScheduledThreadPool(1); this.executorForFetching.scheduleAtFixedRate(new FetchingThread(), 5000, this.fetchingExecutingInterval, TimeUnit.MILLISECONDS); this.executorForOutputing.scheduleAtFixedRate(new OutputThread(), 5000, this.outputingExecutingInterval, TimeUnit.MILLISECONDS); } @PreDestroy public void destroy(){ // 关闭线程 this.executorForFetching.shutdown(); this.executorForOutputing.shutdown(); } class FetchingThread implements Runnable{ @Override public void run() { try{ // 采集JVM指标 ClassLoadingMetric classLoadingMetrics = classLoadingProvider.getClassLoadingMetrics(); JvmMemoryMetric jvmMemoryMetrics = memoryProvider.getJvmMemoryMetrics(); ThreadMetric threadMetrics = threadProvider.getClassLoadingMetrics(); MonitorDataItem jvmMetricsItem = MonitorDataItem.metricItem() .withMetricName(METRIC_NAME_APP_INSTANCE_JVM_MEM) .withMetricField(METRIC_FIELD_NAME_LOADEDCLASSES, classLoadingMetrics.getLoadedClasses()) .withMetricField(METRIC_FIELD_NAME_TOTALLOADEDCLASSES, classLoadingMetrics.getTotalLoadedClasses()) .withMetricField(METRIC_FIELD_NAME_UNLOADEDCLASSES, classLoadingMetrics.getUnloadedClasses()) .withMetricField(METRIC_FIELD_NAME_CODECACHEALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getCodeCacheAllocated())) .withMetricField(METRIC_FIELD_NAME_CODECACHEMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getCodeCacheMax())) .withMetricField(METRIC_FIELD_NAME_CODECACHEUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getCodeCacheUsed())) .withMetricField(METRIC_FIELD_NAME_EDENALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getEdenAllocated())) .withMetricField(METRIC_FIELD_NAME_EDENMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getEdenMax())) .withMetricField(METRIC_FIELD_NAME_EDENUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getEdenUsed())) .withMetricField(METRIC_FIELD_NAME_HEAPALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getHeapAllocated())) .withMetricField(METRIC_FIELD_NAME_HEAPMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getHeapMax())) .withMetricField(METRIC_FIELD_NAME_HEAPUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getHeapUsed())) .withMetricField(METRIC_FIELD_NAME_METASPACEALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getMetaspaceAllocated())) .withMetricField(METRIC_FIELD_NAME_METASPACEMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getMetaspaceMax())) .withMetricField(METRIC_FIELD_NAME_METASPACEUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getMetaspaceUsed())) .withMetricField(METRIC_FIELD_NAME_NONHEAPALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getNonHeapAllocated())) .withMetricField(METRIC_FIELD_NAME_NONHEAPMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getNonHeapMax())) .withMetricField(METRIC_FIELD_NAME_NONHEAPUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getNonHeapUsed())) .withMetricField(METRIC_FIELD_NAME_OLDALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getOldAllocated())) .withMetricField(METRIC_FIELD_NAME_OLDMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getOldMax())) .withMetricField(METRIC_FIELD_NAME_OLDUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getOldUsed())) .withMetricField(METRIC_FIELD_NAME_PERMGENALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getPermGenAllocated())) .withMetricField(METRIC_FIELD_NAME_PERMGENMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getPermGenMax())) .withMetricField(METRIC_FIELD_NAME_PERMGENUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getPermGenUsed())) .withMetricField(METRIC_FIELD_NAME_SURVIVORALLOCATED, NumConvertUtil.byteToM(jvmMemoryMetrics.getSurvivorAllocated())) .withMetricField(METRIC_FIELD_NAME_SURVIVORMAX, NumConvertUtil.byteToM(jvmMemoryMetrics.getSurvivorMax())) .withMetricField(METRIC_FIELD_NAME_SURVIVORUSED, NumConvertUtil.byteToM(jvmMemoryMetrics.getSurvivorUsed())) .withMetricField(METRIC_FIELD_NAME_DAEMONTHREAD, threadMetrics.getDaemonThreads()) .withMetricField(METRIC_FIELD_NAME_LIVINGTHREADS, threadMetrics.getLivingThreads()) .withMetricField(METRIC_FIELD_NAME_PEAKTHREADS, threadMetrics.getPeakThreads()) .withMetricField(METRIC_FIELD_NAME_TOTALTHREADS, threadMetrics.getTotalThreads()) .build(); // 采集JVM GC指标 GCMetric gcMetrics = gcProvider.getGCMetrics(); MonitorDataItem gcMetricsItem = MonitorDataItem.metricItem() .withMetricName(METRIC_NAME_APP_INSTANCE_JVM_GC) .withMetricField(METRIC_FIELD_NAME_FULLGCCOUNT, gcMetrics.getFullGCCount()) .withMetricField(METRIC_FIELD_NAME_FULLGCTIME, gcMetrics.getFullGCTime()) .withMetricField(METRIC_FIELD_NAME_MINORGCCOUNT, gcMetrics.getMinorGCCount()) .withMetricField(METRIC_FIELD_NAME_MINORGCTIME, gcMetrics.getMinorGCTime()) .build(); try{ cacheOpLock.lock(); metricCache.offer(gcMetricsItem); metricCache.offer(jvmMetricsItem); } finally{ cacheOpLock.unlock(); } } catch(Exception e){ logger.error("获取Jvm指标数据失败:", e); } } } class OutputThread implements Runnable{ @Override public void run() { try{ try{ cacheOpLock.lock(); Queue<MonitorDataItem> q = metricCache; metricCache = metricCacheBck; metricCacheBck = q; } finally{ cacheOpLock.unlock(); } if(!metricCacheBck.isEmpty()){ List<MonitorDataItem> metricItems = new ArrayList<>(); for(int i = 0; i < metricCacheBck.size(); i++){ metricItems.add(metricCacheBck.poll()); } metricOutputer.output(metricItems); } } catch(Exception e){ logger.error("输出Jvm指标数据失败:", e); } } } }
。。。