[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[equinox-dev] Memory management in Eclipse - and equinox


I have been developing a TPTP memory manager that is implemented as a listener framework to broadcast "low memory" events. The proposal is for the platform to provide a listener service that allows clients to register as a listener to low memory events.

package org.eclipse.equinox.memory;
 
import java.util.ArrayList;
import java.util.List;
 
/**
 * This class is a placeholder to collect listeners that want to respond to low memory events.
 * Some listeners may want to clear a cache. Others may want to close editors, entire
 * perspectives, or other resources that consume memory in some form or another.
 * <p>
 * All this memory manager does is keep a list of listeners and provide a way to broadcast
 * a low-memory event. <p>
 * An external policy determines when to trigger a broadcast event to be sent to the
 * listeners.
 * @author Chris Laffra
 * @provisional
 */
public class MemoryManager {
 
 /**
  * Indicates memory is running low at the lowest severity.
  * Listeners are requested to release caches that can easily be recomputed.
  * The java VM is not seriously in problem, but process size is getting higher than
  * is deemed acceptable.
  */
 final public static int LOW = 1;
 
 /**
  * Indicates memory is running low at medium severity.
  * Listeners are requested to release intermediate build results, complex models, etc.
  * Memory is getting low and may cause operating system level stress, such as swapping.
  */
 final public static int SERIOUS = 2;
 
 /**
  * Indicates memory is running low at highest severity.
  * Listeners are requested to do things like close editors and perspectives, close
  * database connections, etc.
  * Restoring these resources and caches constitutes lots of work, but memory is so low that
  * drastic measures are required.
  */
 final public static int CRITICAL = 3;
 
 private static List listeners = new ArrayList();
 
 /**
  * Register a listener with the memory manager. After registering, lhe listener will
  * be notified of
  * situations where memory is running low with an indication of the severity.
  *
  * @param listener  the listener that can clean up memory
  *
  * @provisional
  */
 public static synchronized void addLowMemoryListener(LowMemoryListener listener) {
  if (listener == null) {
   throw new NullPointerException();
  }
  if (!listeners.contains(listener)) {
   listeners.add(listener);
  }
 }
 
 /**
  * Remove a low memory listener.
  *
  * @param listener the listener to remove
  *
  * @provisional
  */
 public static synchronized void removeListener(LowMemoryListener listener) {
  if (listener == null) {
   throw new NullPointerException();
  }
  listeners.remove(listener);
 }
 
 /**
  * Broadcast a low memory event.
  *
  * @param severity either LOW, SERIOUS, or CRITICAL
  */
 public static void broadcastLowMemory(int severity) {
  if (severity < LOW || severity > CRITICAL) {
   throw new IllegalArgumentException(Integer.toString(severity));
  }
  synchronized (listeners) {
   for (int n=listeners.size()-1; n>=0; n--) {
    LowMemoryListener listener = (LowMemoryListener) listeners.get(n);
    if (listener != null) {
     listener.memoryIsLow(severity);
    }
   }
  }
 }
 
 /**
  * @return the current list of listeners
  */
 public static synchronized List getListeners() {
  return new ArrayList(listeners);
 };
}
 

The event looks like this:

package org.eclipse.equinox.memory;
 
/**
 * Extenders of this class listen to low memory events. They typically implement a cache
 * (a intermediate representation of some kind that is expensive to compute and that
 * is expected to be computed more than once on a given input).
 *
 * When memory is low, events will be broadcasted to request cache owners to clean up
 * their caches and hence to free up memory.
 *
 * @author Chris Laffra
 * @provisional
 */
public abstract class LowMemoryListener {
 
 /**
  * Return a user-readable description of the listener, for debugging purposes.
  */
 public abstract String getDescription();
 
 /**
  * Return the number of items in the cache managed by the listener
  *
  * @provisional
  */
 public abstract int getCount();
 
 /**
  * Return an estimate of the total memory (in bytes) consumed by the cache managed
  * by the listener.
  * Return -1 when the size is unknown.
  *
  * @provisional
  */
 public abstract long getSize();
 
 /**
  * Inform the listener that memory is low, indicating severity.
  * severity is one of LOW, SERIOUS, CRITICAL
  *
  * @provisional
  */
 public abstract void memoryIsLow(int severity);
 
}
 

As you can see the above contains no policy implementation that triggers the broadcasting of the "low memory" events.
We expect that code to be application-specific and may requires native code to collect statistics on available
physical memory, current consumption, page fault rate, CPU, etc.

As it stands, the above listener is committed to TPTP HEAD and will be included in a build this week.

Would the equinox project be interested into including this API into Platform core so that more plugins up the stack
can benefit from the api, without needing to buy into TPTP?

I added a screendump of a UI monitor that is included in TPTP that monitors the current caches.
As you can see, I added 6 caches that I found in JDT as an example. When users press the garbage can,
the "low memory CRITICAL" event is broadcasted and the JDT caches react by flushing themselves.
As an experiment, we send out timed "low memory LOW" events.
 
Your feedback is appreciated,

Chris Laffra