bb.util
Class MemoryMonitor

java.lang.Object
  extended by bb.util.MemoryMonitor

public class MemoryMonitor
extends Object

Class which actively monitors the memory state of a JVM looking for issues. Reports events as they are detected to any registered MemoryMonitorListeners.

Monitoring is started by calling startMonitoring, is stopped by calling stopMonitoring, and isMonitoring reports if monitoring is currently active. It is legitimate to start and stop monitoring as often as desired.

There are certain situations where the code has to record information but no reference to an appropriate external handler class is available. A prime example is if during the monitoring or listener callback a Throwable is caught. Rather than write the information to a console that could disappear when the application quits, each instance of this class instead maintains a logger2 field where this information is written to. The current implementation logs to a file in the standard log directory.

This class is multithread safe: almost every method (including private ones) is synchronized. The sole exceptions are the private fireXXX methods. These methods are called internally by this class and interact with arbitrary external MemoryMonitorListener classes. As a strategy to prevent deadlock, it is critical that the thread which calls these fireXXX methods initially owns no locks. Thus, these methods must be unsynchronized, since otherwise the lock on this MemoryMonitor instance would be held.

Author:
Brent Boyer

Nested Class Summary
private  class MemoryMonitor.MonitorTask
          Class which detects memory issues and calls the appropriate fireXXX event notification method.
static class MemoryMonitor.UnitTest
          See the Overview page of the project's javadocs for a general description of this unit test class.
 
Field Summary
private static boolean callRestoreJvm_default
          Default value for the callRestoreJvm param of some of the constructors.
private  long instanceId
          Records this instance's Id.
private static AtomicLong instanceIdNext
          The next MemoryMonitor instance's instanceId field.
private  long interval
          Specifies how often the memory state should be checked.
private static long interval_default
          Default value for interval.
private  Set<MemoryMonitorListener> listeners
          Set of all MemoryMonitorListeners that are interested in memory events.
private  Logger2 logger2
          Logger2 where certain information (e.g. otherwise unhandleable errors) gets written to.
private  boolean memoryLow
          Records whether or not low memory has been detected.
private static double memoryLowTrigger_default
          A default value for the memoryLowTrigger arg to the MemoryMonitor constructor (which is subsequently assigned to the MemoryMonitor.MonitorTask.memoryLowTrigger field).
private  MemoryMonitor.MonitorTask monitorTask
          MemoryMonitor.MonitorTask used to measure the memory state.
private  int nextLoggerId
          The next logger2's Id.
private  int nextTimerId
          The next timer value's Id.
private  MemoryState state
          Last memory state that was detected.
private  Timer timer
           
 
Constructor Summary
MemoryMonitor()
          Simply calls this(callRestoreJvm_default, interval_default).
MemoryMonitor(boolean callRestoreJvm, long interval)
          Simply calls this(new MemoryMeasurer.MemoryMeasurer(), memoryLowTrigger_default, interval).
MemoryMonitor(MemoryMeasurer measurer, double memoryLowTrigger, long interval)
          Constructor.
 
Method Summary
 boolean addListener(MemoryMonitorListener listener)
          Attempts to add listener to an internal set.
private  void fireOnMemoryLow(MemoryState state)
           
private  void fireOnMemoryNotLow(MemoryState state)
           
private  void fireOnMemoryState(MemoryState state)
           
private  void fireOnMonitoringError(Throwable t)
           
private  void fireOnMonitoringStarted()
           
private  void fireOnMonitoringStopped()
           
private  void flushLoggerIfCreated()
          Flushes logger2 if and only if it has been created.
private  MemoryMonitorListener[] getListeners()
          Returns a defensive copy of listeners for use by the fireXXX methods.
private  Logger2 getLogger2()
          Returns logger2, lazy initializing it if necessary.
private  String getLoggerSuffix()
          Returns a suffix to assign to logger2's filename whenever it is assigned.
private  boolean getMemoryLow()
           
 MemoryState getMemoryState()
          Returns the memory state that was detected at the last check cycle.
private  String getTimerName()
          Returns a name to assign to timer whenever it is assigned.
 boolean isMemoryLow()
          Reports whether or not the low memory state was detected at the last check cycle.
 boolean isMonitoring()
          Reports whether or not this instance is actively monitoring memory.
 boolean removeListener(MemoryMonitorListener listener)
          Attempts to remove listener from an internal set.
private  void setMemoryLow(boolean memoryLow)
           
private  void setMemoryState(MemoryState state)
           
 boolean startMonitoring()
          Starts monitoring if it is currently not happening.
 boolean stopMonitoring()
          Stops monitoring if it is currently happening.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

callRestoreJvm_default

private static final boolean callRestoreJvm_default
Default value for the callRestoreJvm param of some of the constructors.

The value for this constant is false (i.e. restoreJvm will not be called before each memory measurement).

See Also:
Constant Field Values

interval_default

private static final long interval_default
Default value for interval.

The value for this constant is 1 second. See benchmark_impactOfMonitoring for why it was determined that this value should not burden a JVM excessively.

See Also:
Constant Field Values

memoryLowTrigger_default

private static final double memoryLowTrigger_default
A default value for the memoryLowTrigger arg to the MemoryMonitor constructor (which is subsequently assigned to the MemoryMonitor.MonitorTask.memoryLowTrigger field).

See Also:
Constant Field Values

instanceIdNext

private static final AtomicLong instanceIdNext
The next MemoryMonitor instance's instanceId field.

Contract: is initialized to 0, and if this field has that value, it means that no instances have been created.


instanceId

private final long instanceId
Records this instance's Id.


timer

private Timer timer

nextTimerId

private int nextTimerId
The next timer value's Id.

Contract: is initialized to 1, and if this field has that value, it means that timer has never been assigned.


monitorTask

private final MemoryMonitor.MonitorTask monitorTask
MemoryMonitor.MonitorTask used to measure the memory state.

Contract: is never null.


interval

private final long interval
Specifies how often the memory state should be checked.

Units: milliseconds.

Contract: is > 0.


state

private MemoryState state
Last memory state that was detected. Will be null if no such state was ever detected (e.g. if monitoring was never started).


memoryLow

private boolean memoryLow
Records whether or not low memory has been detected.


listeners

private final Set<MemoryMonitorListener> listeners
Set of all MemoryMonitorListeners that are interested in memory events.

Contract: is never null nor contains null elements.


logger2

private Logger2 logger2
Logger2 where certain information (e.g. otherwise unhandleable errors) gets written to.

Note: this field is lazy initialized inside getLogger2 (because this field will never be used in well behaved applications), may be flushed in flushLoggerIfCreated (if previously initialized), and is closed and nulled out in stopMonitoring (if previously initialized). All other code should always use getLogger2 and never directly access this field.


nextLoggerId

private int nextLoggerId
The next logger2's Id.

Contract: is initialized to 1, and if this field has that value, it means that logger2 has never been assigned.

Constructor Detail

MemoryMonitor

public MemoryMonitor()
Simply calls this(callRestoreJvm_default, interval_default).


MemoryMonitor

public MemoryMonitor(boolean callRestoreJvm,
                     long interval)
Simply calls this(new MemoryMeasurer.MemoryMeasurer(), memoryLowTrigger_default, interval).


MemoryMonitor

public MemoryMonitor(MemoryMeasurer measurer,
                     double memoryLowTrigger,
                     long interval)
              throws IllegalArgumentException
Constructor.

Throws:
IllegalArgumentException - if measurer == null; memoryLowTrigger is NaN, infinite, or outside the range [0, 1]; interval <= 0
Method Detail

startMonitoring

public boolean startMonitoring()
Starts monitoring if it is currently not happening. Specifically, it will create a daemon Timer that executes monitorTask at a rate specified by interval.

This method may safely be called multiple times (if the first call succeeds, subsequent calls do nothing).

Returns:
true if this call actually started the monitoring, false if this instance was already monitoring when called

getTimerName

private String getTimerName()
Returns a name to assign to timer whenever it is assigned. Attempts to return a value that is both unique to this instance as well as unique to each of this instance's timer values.


isMonitoring

public boolean isMonitoring()
Reports whether or not this instance is actively monitoring memory.


stopMonitoring

public boolean stopMonitoring()
Stops monitoring if it is currently happening.

This method may safely be called multiple times (if the first call succeeds, subsequent calls do nothing).

Returns:
true if this call actually stopped the monitoring, false if this instance was not monitoring when called

getMemoryState

public MemoryState getMemoryState()
                           throws IllegalStateException
Returns the memory state that was detected at the last check cycle.

This method never causes a new memory measurement to be made, so it executes extremely quickly, and may be called frequently with low impact on the JVM. On the other hand, the result may be obsolete, especially if this instance was constructed with a large value for interval.

Throws:
IllegalStateException - if instance is currently not monitoring (i.e. isMonitoring returns false)

setMemoryState

private void setMemoryState(MemoryState state)

isMemoryLow

public boolean isMemoryLow()
                    throws IllegalStateException
Reports whether or not the low memory state was detected at the last check cycle.

This method never causes a new memory measurement to be made, so it executes extremely quickly, and may be called frequently with low impact on the JVM. On the other hand, the result may be obsolete, especially if this instance was constructed with a large value for interval.

Throws:
IllegalStateException - if instance is currently not monitoring (i.e. isMonitoring returns false)

getMemoryLow

private boolean getMemoryLow()

setMemoryLow

private void setMemoryLow(boolean memoryLow)

getListeners

private MemoryMonitorListener[] getListeners()
Returns a defensive copy of listeners for use by the fireXXX methods. This is important both for multithread safety (see this class's javadocs) and for reasons explained in this forum posting.


addListener

public boolean addListener(MemoryMonitorListener listener)
                    throws IllegalArgumentException
Attempts to add listener to an internal set.

Returns:
true if listener was added by this call to the internal set, false if already present
Throws:
IllegalArgumentException - if listener == null

removeListener

public boolean removeListener(MemoryMonitorListener listener)
                       throws IllegalArgumentException
Attempts to remove listener from an internal set.

Returns:
true if listener was removed by this call from the internal set, false if already absent
Throws:
IllegalArgumentException - if listener == null

fireOnMonitoringStarted

private void fireOnMonitoringStarted()

fireOnMonitoringStopped

private void fireOnMonitoringStopped()

fireOnMonitoringError

private void fireOnMonitoringError(Throwable t)

fireOnMemoryState

private void fireOnMemoryState(MemoryState state)

fireOnMemoryLow

private void fireOnMemoryLow(MemoryState state)

fireOnMemoryNotLow

private void fireOnMemoryNotLow(MemoryState state)

getLogger2

private Logger2 getLogger2()
Returns logger2, lazy initializing it if necessary.


getLoggerSuffix

private String getLoggerSuffix()
Returns a suffix to assign to logger2's filename whenever it is assigned. Attempts to return a value that is both unique to this instance as well as unique to each of this instance's logger2 values.


flushLoggerIfCreated

private void flushLoggerIfCreated()
Flushes logger2 if and only if it has been created.