001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.support.metric;
017
018import java.lang.management.ManagementFactory;
019import java.lang.management.MemoryPoolMXBean;
020import java.lang.management.MemoryType;
021import java.lang.management.MemoryUsage;
022import java.util.Optional;
023import java.util.function.ToLongFunction;
024
025/**
026 * 参考 MicroMeter
027 */
028class JvmGcUtil {
029
030    private JvmGcUtil() {
031    }
032
033    static Optional<MemoryPoolMXBean> getLongLivedHeapPool() {
034        return ManagementFactory
035                .getPlatformMXBeans(MemoryPoolMXBean.class)
036                .stream()
037                .filter(JvmGcUtil::isHeap)
038                .filter(mem -> isOldGenPool(mem.getName()) || isNonGenerationalHeapPool(mem.getName()))
039                .findAny();
040    }
041
042    static boolean isConcurrentPhase(String cause, String name) {
043        return "No GC".equals(cause)
044                || "Shenandoah Cycles".equals(name);
045    }
046
047    static boolean isYoungGenPool(String name) {
048        return name != null && name.endsWith("Eden Space");
049    }
050
051    static boolean isOldGenPool(String name) {
052        return name != null && (name.endsWith("Old Gen") || name.endsWith("Tenured Gen"));
053    }
054
055    static boolean isNonGenerationalHeapPool(String name) {
056        return "Shenandoah".equals(name) || "ZHeap".equals(name);
057    }
058
059    private static boolean isHeap(MemoryPoolMXBean memoryPoolBean) {
060        return MemoryType.HEAP.equals(memoryPoolBean.getType());
061    }
062
063    static double getUsageValue(MemoryPoolMXBean memoryPoolMXBean, ToLongFunction<MemoryUsage> getter) {
064        MemoryUsage usage = getUsage(memoryPoolMXBean);
065        if (usage == null) {
066            return Double.NaN;
067        }
068        return getter.applyAsLong(usage);
069    }
070
071    private static MemoryUsage getUsage(MemoryPoolMXBean memoryPoolMXBean) {
072        try {
073            return memoryPoolMXBean.getUsage();
074        } catch (InternalError e) {
075            // Defensive for potential InternalError with some specific JVM options. Based on its Javadoc,
076            // MemoryPoolMXBean.getUsage() should return null, not throwing InternalError, so it seems to be a JVM bug.
077            return null;
078        }
079    }
080}