InternalLoggerRegistry is essentially a Map<MessageFactory, Map<String, WeakReference<Logger>>>. As reported by @tristantarrant in #3399, stale entries are not expunged in its current form. That is, the inner map does not get compacted for entries whose associated WeakReferences are reclaimed by the garbage collector. This might cause high memory usage if an excessive amount of ephemeral loggers get registered.
Reclaimed references can be tracked by a ReferenceQueue passed to the WeakReference::new and processed as follows:
private final ReferenceQueue<Logger> staleLoggerRefs = new ReferenceQueue<>();
private void expungeStaleEntries() {
Reference<? extends Logger> loggerRef;
while ((loggerRef = staleLoggerRefs.poll()) != null) {
Logger logger = loggerRef.get();
if (logger != null) {
removeLogger(logger);
}
}
}
When to run expungeStaleEntries() should be decided with care, since removeLogger() mutates the registry map.
On method invocation
All ILR methods (getLogger(), computeIfAbsent(), etc.) can first try to expunge stale entries.
This approach is exercised by WeakHashMap itself and in #3427.
Pros:
- Implies no changes besides
ILR
Cons:
- Read-only operations, which are accessed most, might try to acquire the write-lock.
- If
ILR is not accessed, stale entries will still be kept. Consider an application where all Loggers are assigned, and a temporary operation creates excessive amount of loggers and completes. All created temporary Logger instances will be reclaimed by GC, yet will continue taking space for the associated Map.Entry<String, WeakReference<Logger>>.
By a janitor thread
ILR can start a janitor thread listening on the ReferenceQueue<Logger>.
Cons:
ILR must have a life cycle (to start/stop the janitor thread) managed by LoggerContext.
InternalLoggerRegistryis essentially aMap<MessageFactory, Map<String, WeakReference<Logger>>>. As reported by @tristantarrant in #3399, stale entries are not expunged in its current form. That is, the inner map does not get compacted for entries whose associatedWeakReferences are reclaimed by the garbage collector. This might cause high memory usage if an excessive amount of ephemeral loggers get registered.Reclaimed references can be tracked by a
ReferenceQueuepassed to theWeakReference::newand processed as follows:When to run
expungeStaleEntries()should be decided with care, sinceremoveLogger()mutates the registry map.On method invocation
All
ILRmethods (getLogger(),computeIfAbsent(), etc.) can first try to expunge stale entries.This approach is exercised by
WeakHashMapitself and in #3427.Pros:
ILRCons:
ILRis not accessed, stale entries will still be kept. Consider an application where allLoggers are assigned, and a temporary operation creates excessive amount of loggers and completes. All created temporaryLoggerinstances will be reclaimed by GC, yet will continue taking space for the associatedMap.Entry<String, WeakReference<Logger>>.By a janitor thread
ILRcan start a janitor thread listening on theReferenceQueue<Logger>.Cons:
ILRmust have a life cycle (to start/stop the janitor thread) managed byLoggerContext.