]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics/src/org/simantics/MemoryWarningSystem.java
Support using a DB baseline for faster program startup.
[simantics/platform.git] / bundles / org.simantics / src / org / simantics / MemoryWarningSystem.java
1 package org.simantics;
2
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;
10
11 /**
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
15  * number.
16  * 
17  * ( adapted from http://www.javaspecialists.eu/archive/Issue092.html )
18  * 
19  * @author Antti Villberg
20  */
21 public class MemoryWarningSystem {
22
23     public interface MemoryWarningListener {
24         void memoryLow(long usedMemory);
25     }
26
27     private final Collection<MemoryWarningListener> listeners = new CopyOnWriteArrayList<MemoryWarningListener>();
28
29     private static final MemoryPoolMXBean tenuredGenPool = findTenuredGenPool();
30
31     private double percentage = 1.0;
32
33     private ScheduledFuture<?> future;
34
35     private boolean disposed = false;
36
37     public MemoryWarningSystem(int amount, TimeUnit unit) {
38 //        MemoryMXBean mbean = ManagementFactory.getMemoryMXBean();
39 //        NotificationEmitter emitter = (NotificationEmitter) mbean;
40 //        emitter.addNotificationListener(new NotificationListener() {
41 //            @Override
42 //            public void handleNotification(Notification n, Object hb) {
43 //                if (n.getType().equals(
44 //                        MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED)) {
45 //                      if(!check()) {
46 //                              long used = getUsed();
47 //                              for (MemoryWarningListener listener : listeners) {
48 //                                      listener.memoryLow(used);
49 //                              }
50 //                      }
51 //                      setPercentageUsageThreshold(percentage);
52 //                }
53 //            }
54 //        }, null, null);
55
56         future = Simantics.scheduleAtFixedRate(new Runnable() {
57
58                 @Override
59                 public void run() {
60                         if(!disposed && !check()) {
61                                 long bytes = get();
62                                 for (MemoryWarningListener listener : listeners) {
63                                         listener.memoryLow(bytes);
64                                 }
65                         }
66                 }
67
68         }, 0, amount, unit);
69
70     }
71     
72     public long get() {
73         return tenuredGenPool.getUsage().getUsed();
74     }
75     
76     public boolean check() {
77         long max = Runtime.getRuntime().maxMemory();
78         long usedMemory = get();
79         long threshold = (long)(max * percentage);
80         return usedMemory < threshold;
81     }
82     
83     public long getUsed() {
84         return tenuredGenPool.getUsage().getUsed();
85     }
86
87     public boolean addListener(MemoryWarningListener listener) {
88         return listeners.add(listener);
89     }
90
91     public boolean removeListener(MemoryWarningListener listener) {
92         return listeners.remove(listener);
93     }
94
95     public void setPercentageUsageThreshold(double percentage) {
96         if (percentage <= 0.0 || percentage > 1.0) {
97             throw new IllegalArgumentException("Percentage not in range");
98         }
99         this.percentage = percentage;
100 //        long maxMemory = Runtime.getRuntime().maxMemory();
101 //        long warningThreshold = (long) (maxMemory * percentage);
102 //        tenuredGenPool.setUsageThreshold(0);
103 //        tenuredGenPool.setUsageThreshold(warningThreshold);
104     }
105
106     /**
107      * Tenured Space Pool can be determined by it being of type HEAP and by it
108      * being possible to set the usage threshold.
109      */
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()) {
116                 return pool;
117             }
118         }
119         throw new IllegalStateException("Could not find tenured space");
120     }
121
122     public void dispose() {
123         if (!disposed) {
124             disposed = true;
125             future.cancel(false);
126             listeners.clear();
127        }
128     }
129
130 }