首页 > 代码库 > MemoryMXBean和MemoryPoolMXBean--OutOfMemoryError Warning System

MemoryMXBean和MemoryPoolMXBean--OutOfMemoryError Warning System

MemoryMXBean可以通过ManagementFactory.getMemoryMXBean()获取,也可以通过平台MBeanServer的ObjectName为java.lang:type=Memory获取

MemoryPoolMXBean可以通过ManagementFactory.getMemoryPoolMXBean()获取,也可以通过平台MBeanServer的ObjectName为java.lang:type=MemoryPool,name={pool‘s name}获取

MemoryMXBean的实现MemoryImpl是一个NotificationEmitter类的子类,可以通过addNotificationListener来添加监控;可以监控到MemoryNotificationInfo中定义的两种通知(MEMORY_THRESHOLD_EXCEDED和MEMORY_COLLECTION_THRESHOLD_EXCEEDED,二者区别是是否对不使用的对象经过回收)。

MemoryPoolMXBean可以检测到堆和非堆内存的所有信息,可以清楚的看到Code Cache、Eden Space、Survivor Space、Tenured Gen、Perm Gen等虚拟机内存的信息,通过getUsage()和getPeakUsage()获取信息,通过轮询和通知的方式对阈值进行监控。

注意,我在eclipse中对MemoryMXBean.addNotificationListener中添加的NotificationListener的handleNotification方法设置断点,并未起效,原因可能是Low Memory Detector不支持Java Debug协议,eclipse无法在上面设置断点造成的。

OOME预防可以通过上述工具完成。

首先设置VM arguments Xmx和Xms

代码如下

import javax.management.*;
import java.lang.management.*;
import java.util.*;

/**
 * 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.
 */
public class MemoryWarningSystem {
  private final Collection<Listener> listeners =
      new ArrayList<Listener>();

  public interface Listener {
    public void memoryUsageLow(long usedMemory, long maxMemory);
  }

  public MemoryWarningSystem() {
    MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
    NotificationEmitter emitter = (NotificationEmitter) mbean;
    emitter.addNotificationListener(new NotificationListener() {
      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);
  }

  private static final MemoryPoolMXBean tenuredGenPool =
      findTenuredGenPool();

  public static 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 AssertionError("Could not find tenured space");
  }
}

使用MemTest测试

import java.util.*;

public class MemTest {
  public static void main(String[] args) {
    MemoryWarningSystem.setPercentageUsageThreshold(0.6);

    MemoryWarningSystem mws = new MemoryWarningSystem();
    mws.addListener(new MemoryWarningSystem.Listener() {
      public void memoryUsageLow(long usedMemory, long maxMemory) {
        System.out.println("Memory usage low!!!");
        double percentageUsed = ((double) usedMemory) / maxMemory;
        System.out.println("percentageUsed = " + percentageUsed);
        MemoryWarningSystem.setPercentageUsageThreshold(0.8);
      }
    });

    Collection<Double> numbers = new LinkedList<Double>();
    while (true) {
      numbers.add(Math.random());
    }
  }
}

产生结果如下


Memory usage low!!!
percentageUsed = 0.6281726667795322
Memory usage low!!!
percentageUsed = 0.8504659318016649
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space


来源:http://www.javaspecialists.co.za/archive/Issue092.html

参考:http://java-boy.iteye.com/blog/464953