3 import java.lang.management.ManagementFactory;
4 import java.lang.management.MemoryPoolMXBean;
5 import java.lang.management.MemoryType;
6 import java.util.Collection;
7 import java.util.concurrent.CopyOnWriteArrayList;
8 import java.util.concurrent.ScheduledFuture;
9 import java.util.concurrent.TimeUnit;
12 * This memory warning system will call the listener when we exceed the
13 * percentage of available memory specified. There should only be one instance
14 * of this object created, since the usage threshold can only be set to one
17 * ( adapted from http://www.javaspecialists.eu/archive/Issue092.html )
19 * @author Antti Villberg
21 public class MemoryWarningSystem {
23 public interface MemoryWarningListener {
24 void memoryLow(long usedMemory);
27 private final Collection<MemoryWarningListener> listeners = new CopyOnWriteArrayList<MemoryWarningListener>();
29 private static final MemoryPoolMXBean tenuredGenPool = findTenuredGenPool();
31 private double percentage = 1.0;
33 private ScheduledFuture<?> future;
35 private boolean disposed = false;
37 public MemoryWarningSystem(int amount, TimeUnit unit) {
38 // MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
39 // NotificationEmitter emitter = (NotificationEmitter) mbean;
40 // emitter.addNotificationListener(new NotificationListener() {
42 // public void handleNotification(Notification n, Object hb) {
43 // if (n.getType().equals(
44 // MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
46 // long used = getUsed();
47 // for (MemoryWarningListener listener : listeners) {
48 // listener.memoryLow(used);
51 // setPercentageUsageThreshold(percentage);
56 future = Simantics.scheduleAtFixedRate(new Runnable() {
60 if(!disposed && !check()) {
62 for (MemoryWarningListener listener : listeners) {
63 listener.memoryLow(bytes);
73 return tenuredGenPool.getUsage().getUsed();
76 public boolean check() {
77 long max = Runtime.getRuntime().maxMemory();
78 long usedMemory = get();
79 long threshold = (long)(max * percentage);
80 return usedMemory < threshold;
83 public long getUsed() {
84 return tenuredGenPool.getUsage().getUsed();
87 public boolean addListener(MemoryWarningListener listener) {
88 return listeners.add(listener);
91 public boolean removeListener(MemoryWarningListener listener) {
92 return listeners.remove(listener);
95 public void setPercentageUsageThreshold(double percentage) {
96 if (percentage <= 0.0 || percentage > 1.0) {
97 throw new IllegalArgumentException("Percentage not in range");
99 this.percentage = percentage;
100 // long maxMemory = Runtime.getRuntime().maxMemory();
101 // long warningThreshold = (long) (maxMemory * percentage);
102 // tenuredGenPool.setUsageThreshold(0);
103 // tenuredGenPool.setUsageThreshold(warningThreshold);
107 * Tenured Space Pool can be determined by it being of type HEAP and by it
108 * being possible to set the usage threshold.
110 private static MemoryPoolMXBean findTenuredGenPool() {
111 for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) {
112 // I don't know whether this approach is better, or whether
113 // we should rather check for the pool name "Tenured Gen"?
114 if (pool.getType() == MemoryType.HEAP
115 && pool.isUsageThresholdSupported()) {
119 throw new IllegalStateException("Could not find tenured space");
122 public void dispose() {
125 future.cancel(false);