KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > runtime > TCMemoryManagerImpl


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.runtime;
5
6 import com.tc.logging.TCLogger;
7 import com.tc.logging.TCLogging;
8 import com.tc.util.DebugUtil;
9 import com.tc.util.runtime.Os;
10
11 import java.util.ArrayList JavaDoc;
12 import java.util.Iterator JavaDoc;
13 import java.util.List JavaDoc;
14
15 public class TCMemoryManagerImpl implements TCMemoryManager {
16
17   private static final TCLogger logger = TCLogging.getLogger(TCMemoryManagerImpl.class);
18
19   private final List JavaDoc listeners = new ArrayList JavaDoc();
20
21   private final int threshold;
22   private final int criticalThreshold;
23   private final int leastCount;
24   private final long sleepInterval;
25   private final boolean monitorOldGenOnly;
26
27   private MemoryMonitor monitor;
28
29   public TCMemoryManagerImpl(int usedThreshold, int usedCriticalThreshold, long sleepInterval, int leastCount,
30                              boolean monitorOldGenOnly) {
31     verifyInput(usedThreshold, usedCriticalThreshold, sleepInterval, leastCount);
32     this.monitorOldGenOnly = monitorOldGenOnly;
33     this.leastCount = leastCount;
34     this.threshold = usedThreshold;
35     this.criticalThreshold = usedCriticalThreshold;
36     this.sleepInterval = sleepInterval;
37   }
38
39   private void verifyInput(int usedT, int usedCT, long sleep, int lc) {
40     if (usedT <= 0 || usedT >= 100) {
41       //
42
throw new AssertionError JavaDoc("Used Threshold should be > 0 && < 100 : " + usedT + " Outside range");
43     }
44     if (usedCT <= 0 || usedCT >= 100) {
45       //
46
throw new AssertionError JavaDoc("Critical Used Threshold should be > 0 && < 100 : " + usedCT + " Outside range");
47     }
48     if (usedT > usedCT) {
49       //
50
throw new AssertionError JavaDoc("Used Threshold should be <= Critical Used Threshold : " + usedT + " <= " + usedCT);
51     }
52     if (sleep <= 0) {
53       //
54
throw new AssertionError JavaDoc("Sleep Interval cannot be <= 0 : sleep Interval = " + sleep);
55     }
56     if (lc <= 0 || lc >= 100) {
57       //
58
throw new AssertionError JavaDoc("Least Count should be > 0 && < 100 : " + lc + " Outside range");
59     }
60   }
61
62   public synchronized void registerForMemoryEvents(MemoryEventsListener listener) {
63     listeners.add(listener);
64     startMonitorIfNecessary();
65   }
66
67   public synchronized void unregisterForMemoryEvents(MemoryEventsListener listener) {
68     listeners.remove(listener);
69     stopMonitorIfNecessary();
70   }
71
72   private void stopMonitorIfNecessary() {
73     if (listeners.size() == 0 && monitor != null) {
74       monitor.stop();
75       monitor = null;
76     }
77   }
78
79   private void startMonitorIfNecessary() {
80     if (listeners.size() > 0 && monitor == null) {
81       this.monitor = new MemoryMonitor(TCRuntime.getJVMMemoryManager(), this.sleepInterval, this.monitorOldGenOnly);
82       Thread JavaDoc t = new Thread JavaDoc(this.monitor);
83       t.setDaemon(true);
84       if (Os.isSolaris()) {
85         t.setPriority(Thread.MAX_PRIORITY);
86         t.setName("TC Memory Monitor(High Priority)");
87       } else {
88         t.setName("TC Memory Monitor");
89       }
90       t.start();
91     }
92   }
93
94   private synchronized void fireMemoryEvent(MemoryEventType type, MemoryUsage mu) {
95     for (Iterator JavaDoc i = listeners.iterator(); i.hasNext();) {
96       MemoryEventsListener listener = (MemoryEventsListener) i.next();
97       listener.memoryUsed(type, mu);
98     }
99   }
100
101   public class MemoryMonitor implements Runnable JavaDoc {
102
103     private final JVMMemoryManager manager;
104     private final boolean oldGen;
105     private volatile boolean run = true;
106     private int lastUsed;
107     private MemoryUsage lastReported;
108     private long sleepTime;
109     private MemoryEventType currentState;
110
111     public MemoryMonitor(JVMMemoryManager manager, long sleepInterval, boolean monitorOldGenOnly) {
112       this.manager = manager;
113       this.sleepTime = sleepInterval;
114       this.oldGen = monitorOldGenOnly && manager.isMemoryPoolMonitoringSupported();
115       this.currentState = MemoryEventType.BELOW_THRESHOLD;
116     }
117
118     public void stop() {
119       run = false;
120     }
121
122     public void run() {
123       logger.debug("Starting Memory Monitor - sleep interval - " + sleepTime);
124       final boolean _oldGen = oldGen;
125       while (run) {
126         try {
127           Thread.sleep(sleepTime);
128           MemoryUsage mu = (_oldGen ? manager.getOldGenUsage() : manager.getMemoryUsage());
129           if (DebugUtil.DEBUG) {
130             logger.info("Memory Usage is : " + mu);
131           }
132           reportUsage(mu);
133           adjust(mu);
134         } catch (Throwable JavaDoc t) {
135           logger.error(t);
136         }
137       }
138       logger.debug("Stopping Memory Monitor - sleep interval - " + sleepTime);
139     }
140
141     private void adjust(MemoryUsage mu) {
142       int usedPercentage = mu.getUsedPercentage();
143       try {
144         if (lastUsed != 0 && lastUsed < usedPercentage) {
145           int diff = usedPercentage - lastUsed;
146           long l_sleep = this.sleepTime;
147           if (diff > leastCount * 1.5 && l_sleep > 1) {
148             // decrease sleep time
149
this.sleepTime = Math.max(1, l_sleep * leastCount / diff);
150             logger.info("Sleep time changed to : " + this.sleepTime);
151           } else if (diff < leastCount * 0.5 && l_sleep < sleepInterval) {
152             // increase sleep time
153
this.sleepTime = Math.min(sleepInterval, l_sleep * leastCount / diff);
154             logger.info("Sleep time changed to : " + this.sleepTime);
155           }
156         }
157       } finally {
158         lastUsed = usedPercentage;
159       }
160     }
161
162     private void reportUsage(MemoryUsage mu) {
163       int usedPercentage = mu.getUsedPercentage();
164       if (usedPercentage < threshold) {
165         if (currentState != MemoryEventType.BELOW_THRESHOLD) {
166           // Send only 1 BELOW_THRESHOLD event
167
fire(MemoryEventType.BELOW_THRESHOLD, mu);
168         }
169       } else if (usedPercentage >= criticalThreshold) {
170         if (!oldGen || currentState != MemoryEventType.ABOVE_CRITICAL_THRESHOLD || isLeastCountReached(usedPercentage)
171             || isGCCompleted(mu)) {
172           // Send an event every time if we are monitoring the entire heap or else if we are monitoring only old gen
173
// then send an event only if greater than least count or if we just reached ABOVE_CRITICAL_THRESHOLD or if a gc took place
174
fire(MemoryEventType.ABOVE_CRITICAL_THRESHOLD, mu);
175         }
176       } else if (currentState != MemoryEventType.ABOVE_THRESHOLD || isLeastCountReached(usedPercentage)) {
177         fire(MemoryEventType.ABOVE_THRESHOLD, mu);
178       }
179     }
180
181     private boolean isGCCompleted(MemoryUsage mu) {
182       return lastReported.getCollectionCount() < mu.getCollectionCount();
183     }
184
185     private boolean isLeastCountReached(int usedPercentage) {
186       return (Math.abs(usedPercentage - lastReported.getUsedPercentage()) >= leastCount);
187     }
188
189     private void fire(MemoryEventType type, MemoryUsage mu) {
190       fireMemoryEvent(type, mu);
191       currentState = type;
192       lastReported = mu;
193     }
194   }
195
196 }
197
Popular Tags