|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||
java.lang.Objectorg.hd.d.pg2k.svrCore.MemoryTools
public final class MemoryTools
This contains utilities for memory intensive/sensitive operations. For example, this can veto or partly serialise memory-intensive operations such as image resizing in order to prevent the JVM running out of memory in a resource-constrained environment such as a Web server.
| Nested Class Summary | |
|---|---|
static interface |
MemoryTools.CacheMiniMap<K,V>
Interface for minimal Map subset for caches of various flavours. |
static interface |
MemoryTools.Compactable
Marker interface indicating that a class is suitable for compacting in memory. |
static interface |
MemoryTools.Internable
Marker interface indicating class is suitable for deduping by intern(). |
static interface |
MemoryTools.RecurrentEmergencyFreeHandle
Interface for emergency-free handles expecting to be called zero-or-more times. |
static class |
MemoryTools.SimpleLRUMap<K,V>
Simplified thread-safe map with fixed capacity that discards excess items in LRU (Least Recently Used) order. |
static class |
MemoryTools.SimpleLRUMapAutoSizeForHitRate<K,V>
Simplified map with fixed capacity bounds that discards excess items in LRU (Least Recently Used) order to meet a hit/miss ratio goal. |
static class |
MemoryTools.SimpleProbabilisticCache<K,V>
Simple and fast 'direct-mapped' or probabilistic/lossy cache map. |
static class |
MemoryTools.SoftReferenceMap<K,V>
Soft cache as highly-threadable (thread-safe) Map which holds each value via a SoftReference and discards mapping when the values are GCed. |
private static class |
MemoryTools.SRCMSoftReference<K,V>
Enqueueable SoftReference for SoftReferenceConcurrentMap. |
| Field Summary | |
|---|---|
private static java.util.concurrent.locks.ReentrantLock |
_dEF_lock
Private lock for _doEmergencyFree(); never null (except possibly during initialisation). |
private static java.util.Queue<java.lang.ref.WeakReference<java.lang.Runnable>> |
_emergencyFreeQueue
Queue of one-shot entries that can be called in an emergency to free memory; never null. |
private static java.util.concurrent.CopyOnWriteArrayList<java.lang.ref.WeakReference<MemoryTools.RecurrentEmergencyFreeHandle>> |
_emergencyFreeQueueRecurrent
Concurrent and thread-safe read-mainly store of permanent emergency-free callbacks; never null once class is initialised. |
private static java.util.Timer |
_eTMUATimer
Timer used to process _emergencyTrimMemoryUseAsync() activity; never null. |
private static int |
_IMS_CHECK_MS
Minimum interval for check/update of _iMS_SR in ms; strictly positive. |
private static long |
_iMS_lastCheck
Time of last check of _iMS_SR; the least significant bit indicates state detected. |
private static java.lang.ref.SoftReference<java.lang.Object> |
_iMS_SR
Used by (and private to) isMemoryStressed() to detect memory stress; never null. |
private static long |
_rMIO_commitedBytes
Bytes of memory ``committed'' to runMemoryIntensiveOperation(). |
private static int |
_rMIO_FREE_MEM_MULT
Multiple of excess free memory there should be before attempting memory-intensive task; strictly positive. |
private static java.lang.Object |
_rMIO_lock
Private lock for runMemoryIntensiveOperation(). |
private static int |
_rMIO_MAX_GC_CALLS
Maximum number of times that we will call System.gc() to free memory; strictly positive. |
private static int |
_rMIO_MAX_GC_FRAC
Maximum fraction of wall-clock time we will spend running GC; strictly positive. |
private static long |
_rMIO_noGCBefore
Time before which System.gc() should not be retried; private to _makeMemoryAvailable(). |
private static java.util.concurrent.locks.ReentrantLock |
_tMU_lock
Private lock for _trimMemoryUse(); never null (except possibly during initialisation). |
private static java.util.Collection<java.lang.ref.WeakReference<MemoryTools.Compactable>> |
_tMU_registered
Thread-safe Collection of registered Compactable instances to containers trimmable at run-time without change to their logical state; never null (except possibly during initialisation). |
private static boolean |
_USE_STRING_INTERN
If true, we trust String.intern() to be sensible and to allow GC of unused entries, and thus we delegate handling of at least some String values to it. |
private static boolean |
FORCE_SINGLE_CPU_MODE
If true then force single-CPU mode. |
private static boolean |
INCR_HOUSEKEEP_EFQ
If true then attempt to incrementally clear the _emergencyFreeQueue in the background. |
private static int |
LOWER_PC_THRESHOLD_FOR_MIN_CAPACITY
Lower percentage threshold of free space to force reported capacity cap to minimum; strictly positive and less than 99. |
private static int |
MAX_INTERN_CONC_POWER
Power of maximum concurrency available in intern(); non-negative (0 in single-CPU mode). |
private static int |
MAX_STRING_INTERN
Strings no longer than this use our storage rather than String.intern(). |
private static int |
MIN_WAIT_AFTER_FAILED_GC
Minimum time before attempting forced GC after previous attempt (ms); strictly positive. |
private static boolean |
NO_MEM_INTENSIVE_CONCURRENCY
If true, only allows one memory-intensive operation to run at once. |
private static boolean |
SINGLE_CPU_MODE
If true then run in single-CPU mode to save some space and time overheads by giving up some concurrency. |
private static int |
TARGET_FREE_FORCE_POLL_MS
Interval between attempts to keep target memory free, ms, strictly positive. |
private static java.util.WeakHashMap<MemoryTools.Internable,java.lang.ref.WeakReference<MemoryTools.Internable>>[] |
WHM_Internables
Private to intern(): for holding Internable values; never null nor zero-size nor containing nulls. |
private static java.util.WeakHashMap<MemoryTools.Internable,java.lang.ref.WeakReference<MemoryTools.Internable>> |
WHM_Internables_0
Private to intern(); reference to 0 element of WHM_Internables as optimisation for single-CPU systems; never null. |
| Constructor Summary | |
|---|---|
private |
MemoryTools()
Prevent creation of instances of this class. |
| Method Summary | ||
|---|---|---|
private static int |
_doEmergencyFree()
Do emergency free/release of memory. |
|
private static void |
_emergencyTrimMemoryUseAsync(boolean doEmergencyFree)
Run _trimMemoryUse(), _doEmergencyFree() if requested plus forced GC, asynchronously. |
|
private static boolean |
_isMemoryStressedQ()
Very quick non-blocking internal poll of stress state. |
|
private static boolean |
_makeMemoryAvailable(long bytes)
Attempt to make sure that the specified amount of memory is available; return true if so. |
|
private static long |
_targetFreeMemory()
Target amount of free heap space (a decent fraction of current heap size). |
|
private static void |
_trimMemoryUse()
Internal routine, thread-safe, to try to (fairly firmly) trim some memory use on demand. |
|
private static int |
computeCapacityCap(int minSize,
int maxCapacity)
Computes target map size cap based on system memory availability; in range [minSize,maxCapacity]. |
|
private static int |
heldInternableCount()
Get current number of Internable items held, and purge any dead entries too. |
|
static
|
intern(E o)
Generic equivalent of String.intern(), for more immutable objects that we care about. |
|
static
|
intern(E o)
Specific overloading of intern() for Number to avoid runtime instanceof cost where possible. |
|
static
|
intern(E o)
Specific overloading of intern() for Internable to avoid runtime instanceof cost where possible. |
|
static java.lang.String |
intern(java.lang.String s)
Specific overloading of intern() for String to avoid runtime instanceof cost where possible. |
|
static boolean |
isMemoryStressed()
Returns true if the memory system may be under (great) stress, eg not enough free. |
|
static boolean |
lotsFree()
True when there's currently lots of memory free and memory is not otherwise stressed. |
|
static int |
percentFreeWithinTarget()
Estimate of percentage of free space remaining as a fraction of the system target; in range[0,100]. |
|
static boolean |
preemptiveGC()
Request a preemptive garbage collection, for example while the system is (too) quiet. |
|
static void |
registerCompactable(MemoryTools.Compactable c)
Allows a local Compactable instance to register itself. |
|
static void |
registerEmergencyFreeHandle(java.lang.Runnable r)
Queue up a handle to be called at most once to release memory on demand when detected to be very low. |
|
static void |
registerRecurrentEmergencyFreeHandle(MemoryTools.RecurrentEmergencyFreeHandle r)
Queue up a handle to be called back as often as necessary to release memory on demand when detected to be very low. |
|
static
|
runMemoryIntensiveOperation(java.util.concurrent.Callable<V> task,
boolean unlimitedMemory,
int estimatedMinBytesRequired)
Wrapper round runMemoryIntensiveOperation(Runnable, ...) for value-returning tasks. |
|
static
|
runMemoryIntensiveOperation(java.util.concurrent.Callable<V> task,
int estimatedMinBytesRequired)
Wrapper round runMemoryIntensiveOperation(Runnable, ...) for value-returning tasks that must always be run. |
|
static boolean |
runMemoryIntensiveOperation(java.lang.Runnable task,
boolean unlimitedMemory,
int estimatedMinBytesRequired)
Run (or veto by refusing to run) a memory-intensive operation. |
|
| Methods inherited from class java.lang.Object |
|---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Field Detail |
|---|
private static volatile java.lang.ref.SoftReference<java.lang.Object> _iMS_SR
Marked volatile for thread-safe lock-free access.
private static volatile long _iMS_lastCheck
Marked volatile for thread-safe lock-free access.
The initial state indicates that stress was not detected.
private static final int _IMS_CHECK_MS
We probably want to be able to detect milder stress than this, so a poll on the order of seconds is probably reasonable, but we try to avoid making this an obvious (sub-)multiple of any regular activity.
private static final java.util.Collection<java.lang.ref.WeakReference<MemoryTools.Compactable>> _tMU_registered
The Collection implementation is unbounded, should make insertion/deletion O(1), and must allow safe/sensible concurrent use of iterator() with other uses/modification and without throwing ConcurrentModificationException so that we can avoid any locking/blocking.
This is intended only to hold a smallish number of potentially-large collections/containers.
private static final boolean INCR_HOUSEKEEP_EFQ
private static final java.util.Queue<java.lang.ref.WeakReference<java.lang.Runnable>> _emergencyFreeQueue
Whenever we detect that memory is under great stress we work through this queue in order calling the target (unless the WeakReference has already expired, in which case we simply discard the entry).
We may periodically purge this queue of expired items to avoid it becoming a problem itself.
Anything that is called by this would need to re-register in order to be called again, ie on the next emergency. It is safe to re-register the same Runnable instance in such a case.
Thread-safe (and its iterators won't ever throw exceptions).
private static final java.util.concurrent.CopyOnWriteArrayList<java.lang.ref.WeakReference<MemoryTools.RecurrentEmergencyFreeHandle>> _emergencyFreeQueueRecurrent
private static final java.util.concurrent.locks.ReentrantLock _tMU_lock
private static final java.util.concurrent.locks.ReentrantLock _dEF_lock
private static final java.util.Timer _eTMUATimer
Avoids having more than one Thread run this concurrently.
We may also run other periodic tasks with this timer. TODO: move expensive/periodic checks to this so that isMemoryStressed() calls all just poll a volatile flag
private static final int TARGET_FREE_FORCE_POLL_MS
private static final boolean NO_MEM_INTENSIVE_CONCURRENCY
We must not hold a lock to enforce this as doing so may cause deadlock; we veto any concurrent call immediately when true.
private static long _rMIO_commitedBytes
Initially zero.
private static volatile long _rMIO_noGCBefore
Initialised with 'now' to postpone the first attempt to force GC.
Is volatile to allow it to be read/written safely without a lock.
private static final java.lang.Object _rMIO_lock
private static final int _rMIO_MAX_GC_FRAC
TODO: we might additionally abort if we've spent more than some fixed time, eg 30s, trying to collect garbage already.
This is used to limit impact on global system performance.
A value between 10 and 100 is probably reasonable.
private static final int MIN_WAIT_AFTER_FAILED_GC
This can be a few seconds through to a few minutes.
private static final int _rMIO_MAX_GC_CALLS
It may be worth calling System.gc() more than once because it may in fact take several passes in some JVMs to liberate all the heap from several different heap areas and across several threads, but calling it lots of times is probably just a huge drain on system resources or may simply be ignored by the JVM.
A value from 1 to 3 inclusive is probably good.
private static final int _rMIO_FREE_MEM_MULT
If we eliminate concurrency between memory-intensive operations then we can be less conservative than we otherwise would be, and indeed can possibly drop this down to 1.
A value in the range 1--4 is probably good.
private static final boolean FORCE_SINGLE_CPU_MODE
private static final boolean SINGLE_CPU_MODE
private static final int MAX_INTERN_CONC_POWER
private static final java.util.WeakHashMap<MemoryTools.Internable,java.lang.ref.WeakReference<MemoryTools.Internable>>[] WHM_Internables
We start this off reasonably large, and with a low load factor, for access performance.
Unless in SINGLE_CPU mode we have many (low-load-factor) maps to usually allow concurrent (and fast) intern() operations.
private static final java.util.WeakHashMap<MemoryTools.Internable,java.lang.ref.WeakReference<MemoryTools.Internable>> WHM_Internables_0
private static final boolean _USE_STRING_INTERN
private static final int MAX_STRING_INTERN
A reasonable value for this threshold is probably in the range -1--1024, for example:
private static final int LOWER_PC_THRESHOLD_FOR_MIN_CAPACITY
| Constructor Detail |
|---|
private MemoryTools()
| Method Detail |
|---|
private static boolean _isMemoryStressedQ()
Can be used to bias allocators, etc.
Can be used in a short-cut conditional such as
(_isMemoryStressedQ() && isMemoryStressed())
to avoid running the full-blown isMemoryStressed()
unless we were recently stressed,
ie is quick if not recently stressed
and doesn't give false positives.
public static final boolean isMemoryStressed()
This may work best if polled reasonably regularly.
This is likely to be at best stochastic, ie more likely to return true under severe memory stress, and less likely to return true when not under significant memory stress.
This checks the clearing of a SoftReference as one measure of memory stress:
This also makes sure that at least a reasonable fraction of the current heap 'total' memory is reported as free.
This may attempt to initiate release of some memory asynchronously when it detects memory stress.
TODO: make use of MemoryPoolMXBean (etc) facilities for more robust detection.
private static long _targetFreeMemory()
public static boolean lotsFree()
public static int percentFreeWithinTarget()
Nominally, if less than 1% of the target amount of free space is available the this returns 0, though an OOME is likely before this is reached.
Lower numbers indicate increasing memory pressure.
public static final void registerCompactable(MemoryTools.Compactable c)
Should be largely wait-free.
This may fail to register an item during initialisation, but in any case no Compactable instance should rely on this to call compact() but should also be doing the equivalent itself, eg on most accessors as per WeakHashMap.
c - fully-constructed non-null Compactable instancepublic static void registerEmergencyFreeHandle(java.lang.Runnable r)
Anything that is called by this would need to re-register in order to be called again, ie on the next emergency. It is safe to re-register the same Runnable instance in such a case, though registering multiple times would be inadvisable.
These handles should ideally run without blocking at all, or at least be quick and avoid deadlock.
Thread-safe.
public static void registerRecurrentEmergencyFreeHandle(MemoryTools.RecurrentEmergencyFreeHandle r)
These entries need not and must not attempt to re-register themselves or be otherwise registered multiple times.
We try very hard to make sure that any significant memory required is allocated (and thus may possibly fail) during registration rather than when attempting to actually use the callbacks, thus maximising the chance of working correctly!
These handles should ideally run without blocking at all, or at least be quick and avoid deadlock.
These are assumed to be added (and expire) infrequently.
Thread-safe.
private static void _trimMemoryUse()
Doesn't force any emergency memory release.
Thread-safe: silently returns if routine already running (lock already held) or in the (unusual) case of the lock not yet initialised/set-up.
private static int _doEmergencyFree()
FIXME: danger of 'losing' handles if we get another OOM here while moving them around.
Thread-safe: silently returns (-1) if already running (lock already held) or in the (unusual) case of the lock not yet initialised/set-up.
private static void _emergencyTrimMemoryUseAsync(boolean doEmergencyFree)
doEmergencyFree - if true then call the emergency-free handlers and possibly force GCprivate static boolean _makeMemoryAvailable(long bytes)
This does not hold any locks.
We try very hard to avoid actually calling System.gc() as doing so may upset the ergonomics of almost any GC implementation, and in particular is quite likely to result in an unwanted long stop-the-world pause.
bytes - approximate number of bytes of heap free required; non-negative
public static <V,E extends java.lang.Exception> V runMemoryIntensiveOperation(java.util.concurrent.Callable<V> task,
int estimatedMinBytesRequired)
throws java.lang.Exception
java.lang.Exception - any exception thrown by the Callable or our handler routine
public static <V> Tuple.Pair<java.lang.Boolean,V> runMemoryIntensiveOperation(java.util.concurrent.Callable<V> task,
boolean unlimitedMemory,
int estimatedMinBytesRequired)
throws java.lang.Exception
java.lang.Exception - any exception thrown by the Callable or our handler routine
public static boolean runMemoryIntensiveOperation(java.lang.Runnable task,
boolean unlimitedMemory,
int estimatedMinBytesRequired)
throws java.lang.IllegalArgumentException,
java.lang.IllegalStateException
The task is run, possibly after a delay, if resources seem to be available for it, and this routine returns true.
If sufficient resource (ie memory) does not seem to be available, then the task is not return and this routine returns false.
This routine may attempt to free memory by calling System.gc() one or more times, but because this may be slow and may impact system performance (eg concurrency) badly, this waits a significant multiple of the time taken to perform GC between such attempts, so this routine may refuse to try to free memory for a task even if it would work.
This keeps a static variable to track memory use between separate (concurrent) callers and is thus implicitly counting memory shared in this JVM or class loader. This routine tries to be robust enough to work reasonably well even with multiple separate copies of this class in separate class loaders within one JVM.
If the unlimitedMemory parameter is true then the task is always run immediately, and can be used for testing and for situations where heap space is freely available, eg the heap may be easily expanded.
No checked exception is propagated to the caller, but a non-checked exception may be.
This routine holds no lock for its duration to avoid deadlocks, but may "baulk" at (ie refuse to run) concurrent calls so as to limit concurrency.
task - the task to be runestimatedMinBytesRequired - estimate of peak number of bytes
of heap that the task will use (overestimate rather than
underestimate this value); must be non-negativeunlimitedMemory - if true, the task is always run
on the assumption that at the moment resources are effectively
unlimited (or at least that this task must be run)
but other memory-intensive tasks may be denied
java.lang.IllegalArgumentException - if the task is null or
a negative amount of memory is specified
java.lang.IllegalStateException - if too much aggregate memory
is being requested between all the concurrent taskspublic static boolean preemptiveGC()
This should be called when the system seems to be idle (in terms of human user, eg Web site visitor, activity) and is likely to idle for (say) a minute or so, to allow us to get in a full GC run while no one is looking, so as we can last as long as possible without an intrusive GC when the system is in use later. This may help recover from (for example) leaked file handles preventing any clients contacting us.
An alternative use is when we can't see a comfortable margin of free memory (possibly even though we've just trimmed significant fat) and we want to try to force such a margin to be visibly free.
private static int heldInternableCount()
public static java.lang.String intern(java.lang.String s)
public static <E extends MemoryTools.Internable> E intern(E o)
public static <E extends java.lang.Number> E intern(E o)
public static <E> E intern(E o)
This generic routine is for where we do not know the type until run-time; the compiler may select a better overloading at compile-time otherwise. Thanks to Peter Ahé of Sun for the suggestion!
Note that lots of immutable/final objects are not suitable for canonicalisation with this routine. Caveat programmer.
A unique instance is returned of the same type.
When the intern method is invoked, if the pool already contains an
Object equal to this Object o as determined by
the equals(Object) method, then the object from the pool is
returned. Otherwise, this Object is added to the
pool and a reference to this Object is returned.
It follows that for any two Objects s and t,
intern(s) == intern(t) is true
if and only if s.equals(t) is true.
Entries are automatically dropped sometime after the last strong/soft reference to them has gone, possibly on the next call to this routine.
Unlike String.intern(), this applies to more than just String elements, and memory is guaranteed to be recoverable from non-referenced items (whereas String.intern() has not always been so and is still not clear in the spec).
It is probably not especially useful to put String constants or other static items in here routinely as their entries are unlikely to become unreferenced.
This routine is likely to be quite slow and have significant overhead, so only use it when not doing so would cause huge memory bloat or churn, and when you expect the intern()ed values to live for a long time.
May not in fact be able to cache/canonicalise all or any objects; mutable objects should never be intern()ed.
Calling this with null returns null.
private static int computeCapacityCap(int minSize,
int maxCapacity)
Always returns Integer.MAX_VALUE if maxCapacity is Integer.MAX_VALUE.
|
DHD Multimedia Gallery V1.57.21 | ||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD | ||||||||