From dac5c85056771724d6abca327e15f93cdc91698d Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Thu, 31 Aug 2023 13:17:05 -0700 Subject: [PATCH] Last part of #1090: remove now obsolete `ThreadLocalBufferManager` too --- .../core/util/ThreadLocalBufferManager.java | 116 ------------------ 1 file changed, 116 deletions(-) delete mode 100644 src/main/java/tools/jackson/core/util/ThreadLocalBufferManager.java diff --git a/src/main/java/tools/jackson/core/util/ThreadLocalBufferManager.java b/src/main/java/tools/jackson/core/util/ThreadLocalBufferManager.java deleted file mode 100644 index 6d945bb9e3..0000000000 --- a/src/main/java/tools/jackson/core/util/ThreadLocalBufferManager.java +++ /dev/null @@ -1,116 +0,0 @@ -package tools.jackson.core.util; - -import java.lang.ref.ReferenceQueue; -import java.lang.ref.SoftReference; - -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -/** - * For issue [jackson-core#400] We keep a separate Set of all SoftReferences to BufferRecyclers - * which are (also) referenced using `ThreadLocals`. - * We do this to be able to release them (dereference) in `releaseBuffers()` and `shutdown()` - * method to reduce heap consumption during hot reloading of services where otherwise - * {@link ClassLoader} would have dangling reference via {@link ThreadLocal}s. - * When gc clears a SoftReference, it puts it on a newly introduced referenceQueue. - * We use this queue to release the inactive SoftReferences from the Set. - * - * @since 2.9.6 - */ -class ThreadLocalBufferManager -{ - /** - * A lock to make sure releaseBuffers is only executed by one thread at a time - * since it iterates over and modifies the allSoftBufRecyclers. - */ - private final Object RELEASE_LOCK = new Object(); - - /** - * A set of all SoftReferences to all BufferRecyclers to be able to release them on shutdown. - * 'All' means the ones created by this class, in this classloader. - * There may be more from other classloaders. - * We use a HashSet to have quick O(1) add and remove operations. - *

- * NOTE: assumption is that {@link SoftReference} has its {@code equals()} and - * {@code hashCode()} implementations defined so that they use object identity, so - * we do not need to use something like {@link IdentityHashMap} - */ - private final Map,Boolean> _trackedRecyclers - = new ConcurrentHashMap, Boolean>(); - - /** - * Queue where gc will put just-cleared SoftReferences, previously referencing BufferRecyclers. - * We use it to remove the cleared softRefs from the above set. - */ - private final ReferenceQueue _refQueue = new ReferenceQueue(); - - /* - /********************************************************** - /* Public API - /********************************************************** - */ - - /** - * Returns the lazily initialized singleton instance - */ - public static ThreadLocalBufferManager instance() { - return ThreadLocalBufferManagerHolder.manager; - } - - /** - * Releases the buffers retained in ThreadLocals. To be called for instance on shutdown event of applications which make use of - * an environment like an appserver which stays alive and uses a thread pool that causes ThreadLocals created by the - * application to survive much longer than the application itself. - * It will clear all bufRecyclers from the SoftRefs and release all SoftRefs itself from our set. - */ - public int releaseBuffers() { - synchronized (RELEASE_LOCK) { - int count = 0; - // does this need to be in sync block too? Looping over Map definitely has to but... - removeSoftRefsClearedByGc(); // make sure the refQueue is empty - for (SoftReference ref : _trackedRecyclers.keySet()) { - ref.clear(); // possibly already cleared by gc, nothing happens in that case - ++count; - } - _trackedRecyclers.clear(); //release cleared SoftRefs - return count; - } - } - - public SoftReference wrapAndTrack(BufferRecycler br) { - SoftReference newRef; - newRef = new SoftReference(br, _refQueue); - // also retain softRef to br in a set to be able to release it on shutdown - _trackedRecyclers.put(newRef, true); - // gc may have cleared one or more SoftRefs, clean them up to avoid a memleak - removeSoftRefsClearedByGc(); - return newRef; - } - - /* - /********************************************************** - /* Internal methods - /********************************************************** - */ - - /** - * Remove cleared (inactive) SoftRefs from our set. Gc may have cleared one or more, - * and made them inactive. We minimize contention by keeping synchronized sections short: - * the poll/remove methods - */ - private void removeSoftRefsClearedByGc() { - SoftReference clearedSoftRef; - while ((clearedSoftRef = (SoftReference) _refQueue.poll()) != null) { - // uses reference-equality, quick, and O(1) removal by HashSet - _trackedRecyclers.remove(clearedSoftRef); - } - } - - /** - * ThreadLocalBufferManagerHolder uses the thread-safe initialize-on-demand, holder class idiom that implicitly - * incorporates lazy initialization by declaring a static variable within a static Holder inner class - */ - private static final class ThreadLocalBufferManagerHolder { - static final ThreadLocalBufferManager manager = new ThreadLocalBufferManager(); - } -}