当内存不足时自动警告 Java 应用程序的好方法是什么?

发布于 2025-01-02 21:39:23 字数 127 浏览 3 评论 0原文

当可用内存达到某个阈值时,是否有一种优雅的方法可以自动向我的 Java 应用程序发出内存警告?

请注意,这是一个 Jeopardy 风格的问题,我已经有了答案,只是想将其发布在这里供全世界发现,因为该解决方案对我有很大帮助。

Is there an elegant way to automatically fire memory warnings to my Java application when free memory reaches a certain threshold?

Note that this is a Jeopardy-style question to which I already have an answer, just wanted to post it here for the world to discover because the solution helped me a bunch.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜未央樱花落 2025-01-09 21:39:23

这是 Heinz Kabutz 编写的一个很棒的小课程,它对我来说“开箱即用”,完美无缺。在旧的“Java Specialists”问题中找到它:http://www.javaspecialists.eu/archive/Issue092.html

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.util.ArrayList;
import java.util.Collection;

import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;

/**
 * This memory warning system will call the listener when we exceed the
 * percentage of available memory specified. There should only be one instance
 * of this object created, since the usage threshold can only be set to one
 * number.
 * 
 * ( adapted from http://www.javaspecialists.eu/archive/Issue092.html )
 */

public class MemoryWarningSystem {

    public interface Listener {

        void memoryUsageLow(long usedMemory, long maxMemory);
    }

    private final Collection<Listener> listeners = new ArrayList<Listener>();

    private static final MemoryPoolMXBean tenuredGenPool = findTenuredGenPool();

    public MemoryWarningSystem() {
        MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
        NotificationEmitter emitter = (NotificationEmitter) mbean;
        emitter.addNotificationListener(new NotificationListener() {
            @Override
            public void handleNotification(Notification n, Object hb) {
                if (n.getType().equals(
                        MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
                    long maxMemory = tenuredGenPool.getUsage().getMax();
                    long usedMemory = tenuredGenPool.getUsage().getUsed();
                    for (Listener listener : listeners) {
                        listener.memoryUsageLow(usedMemory, maxMemory);
                    }
                }
            }
        }, null, null);
    }

    public boolean addListener(Listener listener) {
        return listeners.add(listener);
    }

    public boolean removeListener(Listener listener) {
        return listeners.remove(listener);
    }

    public void setPercentageUsageThreshold(double percentage) {
        if (percentage <= 0.0 || percentage > 1.0) {
            throw new IllegalArgumentException("Percentage not in range");
        }
        long maxMemory = tenuredGenPool.getUsage().getMax();
        long warningThreshold = (long) (maxMemory * percentage);
        tenuredGenPool.setUsageThreshold(warningThreshold);
    }

    /**
     * Tenured Space Pool can be determined by it being of type HEAP and by it
     * being possible to set the usage threshold.
     */
    private static MemoryPoolMXBean findTenuredGenPool() {
        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
            // I don't know whether this approach is better, or whether
            // we should rather check for the pool name "Tenured Gen"?
            if (pool.getType() == MemoryType.HEAP
                    && pool.isUsageThresholdSupported()) {
                return pool;
            }
        }
        throw new IllegalStateException("Could not find tenured space");
    }
}

用法:

    MemoryWarningSystem system = new MemoryWarningSystem();
    system.setPercentageUsageThreshold(0.8d);
    system.addListener(new Listener() {
        @Override
        public void memoryUsageLow(long usedMemory, long maxMemory) {
            System.out.println("low: "+usedMemory+" / "+maxMemory);
        }
    });

Here's a great little class written by Heinz Kabutz that works flawlessly for me "out of the box". Found it in an old "Java specialists" issue: http://www.javaspecialists.eu/archive/Issue092.html

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryNotificationInfo;
import java.lang.management.MemoryPoolMXBean;
import java.lang.management.MemoryType;
import java.util.ArrayList;
import java.util.Collection;

import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationListener;

/**
 * This memory warning system will call the listener when we exceed the
 * percentage of available memory specified. There should only be one instance
 * of this object created, since the usage threshold can only be set to one
 * number.
 * 
 * ( adapted from http://www.javaspecialists.eu/archive/Issue092.html )
 */

public class MemoryWarningSystem {

    public interface Listener {

        void memoryUsageLow(long usedMemory, long maxMemory);
    }

    private final Collection<Listener> listeners = new ArrayList<Listener>();

    private static final MemoryPoolMXBean tenuredGenPool = findTenuredGenPool();

    public MemoryWarningSystem() {
        MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
        NotificationEmitter emitter = (NotificationEmitter) mbean;
        emitter.addNotificationListener(new NotificationListener() {
            @Override
            public void handleNotification(Notification n, Object hb) {
                if (n.getType().equals(
                        MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
                    long maxMemory = tenuredGenPool.getUsage().getMax();
                    long usedMemory = tenuredGenPool.getUsage().getUsed();
                    for (Listener listener : listeners) {
                        listener.memoryUsageLow(usedMemory, maxMemory);
                    }
                }
            }
        }, null, null);
    }

    public boolean addListener(Listener listener) {
        return listeners.add(listener);
    }

    public boolean removeListener(Listener listener) {
        return listeners.remove(listener);
    }

    public void setPercentageUsageThreshold(double percentage) {
        if (percentage <= 0.0 || percentage > 1.0) {
            throw new IllegalArgumentException("Percentage not in range");
        }
        long maxMemory = tenuredGenPool.getUsage().getMax();
        long warningThreshold = (long) (maxMemory * percentage);
        tenuredGenPool.setUsageThreshold(warningThreshold);
    }

    /**
     * Tenured Space Pool can be determined by it being of type HEAP and by it
     * being possible to set the usage threshold.
     */
    private static MemoryPoolMXBean findTenuredGenPool() {
        for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
            // I don't know whether this approach is better, or whether
            // we should rather check for the pool name "Tenured Gen"?
            if (pool.getType() == MemoryType.HEAP
                    && pool.isUsageThresholdSupported()) {
                return pool;
            }
        }
        throw new IllegalStateException("Could not find tenured space");
    }
}

Usage:

    MemoryWarningSystem system = new MemoryWarningSystem();
    system.setPercentageUsageThreshold(0.8d);
    system.addListener(new Listener() {
        @Override
        public void memoryUsageLow(long usedMemory, long maxMemory) {
            System.out.println("low: "+usedMemory+" / "+maxMemory);
        }
    });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文