How to know about OutOfMemory or StackOverflow errors ahead of time

前端 未结 11 1712
余生分开走
余生分开走 2021-02-15 17:10

In Java, is there a way to know that a StackOverflow error or OutOfMemory exception may happen soon?

The OutOfMemory exception m

11条回答
  •  甜味超标
    2021-02-15 17:51

    Implementation example using MemoryPoolMXBean

    import static java.lang.management.ManagementFactory.getMemoryMXBean;
    import static java.lang.management.ManagementFactory.getMemoryPoolMXBeans;
    import static java.lang.management.MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED;
    import static java.lang.management.MemoryType.HEAP;
    import java.lang.management.MemoryPoolMXBean;
    import java.lang.management.MemoryUsage;
    import java.util.Collection;
    import java.util.concurrent.CopyOnWriteArrayList;
    import javax.management.Notification;
    import javax.management.NotificationEmitter;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class MemoryWatcher {
    
        public interface Listener {
            void memoryUsageLow(long usedMemory, long maxMemory);
        }
    
        private static final MemoryPoolMXBean tenuredGenPool = findTenuredGenPool();
        private static final Logger logger = LoggerFactory.getLogger(MemoryWatcher.class);
    
        private static MemoryPoolMXBean findTenuredGenPool() {
            for (MemoryPoolMXBean pool : getMemoryPoolMXBeans())
                if (pool.getType() == HEAP && pool.isUsageThresholdSupported())
                    return pool;
            return null;
        }
    
        public static MemoryPoolMXBean getTenuredGenPool() {
            return tenuredGenPool;
        }
    
        private final Collection listeners = new CopyOnWriteArrayList<>();
    
        public MemoryWatcher(double usageThresholdPercent) {
            if (tenuredGenPool == null) {
                logger.warn("Tenured pool is not used");
                return;
            }
            if (tenuredGenPool.getUsageThreshold() != 0)
                logger.warn("Overriding tenured usage threshold {} with {}", tenuredGenPool.getUsage().getMax() / (double) tenuredGenPool.getUsageThreshold(), usageThresholdPercent);
            tenuredGenPool.setUsageThreshold((long) (tenuredGenPool.getUsage().getMax() * usageThresholdPercent));
    
            NotificationEmitter emitter = (NotificationEmitter) getMemoryMXBean();
            emitter.addNotificationListener((Notification n, Object hb) -> {
                MemoryUsage usage = tenuredGenPool.getUsage();
                if (n.getType().equals(MEMORY_THRESHOLD_EXCEEDED) && usage.getMax() == usage.getCommitted())
                    listeners.forEach(listener -> listener.memoryUsageLow(usage.getUsed(), usage.getMax()));
            }, null, null);
        }
    
        public boolean addListener(Listener listener) {
            return listeners.add(listener);
        }
    
        public boolean removeListener(Listener listener) {
            return listeners.remove(listener);
        }
    }
    

提交回复
热议问题