class ReferenceCountedCache<K, T extends ReferenceCounted & Closeable, V, E extends Throwable>
        extends AbstractCloseable {

    private final Map<K, T> cache = new LinkedHashMap<>();
    private final Function<T, V> transformer;
    private final ThrowingFunction<K, T, E> creator;
    private final ReferenceChangeListener referenceChangeListener;

    public ReferenceCountedCache(final Function<T, V> transformer,
                                 final ThrowingFunction<K, T, E> creator) {
        this.transformer = transformer;
        this.creator = creator;
        this.referenceChangeListener = new TriggerFlushOnLastReferenceRemoval();

        singleThreadedCheckDisabled(true);
    }

    @NotNull
    V get(@NotNull final K key) throws E {
        throwExceptionIfClosed();

        final V rv;
        synchronized (cache) {
            @Nullable T value = cache.get(key);

            if (value == null) {
                value = creator.apply(key);
                value.reserveTransfer(INIT, this);
                value.addReferenceChangeListener(referenceChangeListener);
                //System.err.println("Reserved " + value.toString() + " by " + this);
                cache.put(key, value);
            }

            // this will add to the ref count and so needs to be done inside of sync block
            rv = transformer.apply(value);
        }

        return rv;
    }

    @Override
    protected void performClose() {
        synchronized (cache) {
            for (T value : cache.values()) {
                releaseResource(value);
            }
            cache.clear();
        }
    }

    private void releaseResource(T value) {<FILL_FUNCTION_BODY>}

    public void remove(K key) {
        // harmless to call if cache is already closing/closed

        synchronized (cache) {
            releaseResource(cache.remove(key));
        }
    }

    private class TriggerFlushOnLastReferenceRemoval implements ReferenceChangeListener {

        private final Runnable bgCleanup = this::bgCleanup;

        @Override
        public void onReferenceRemoved(ReferenceCounted referenceCounted, ReferenceOwner referenceOwner) {
            if (referenceOwner != ReferenceCountedCache.this && referenceCounted.refCount() == 1) {
                BackgroundResourceReleaser.run(bgCleanup);
            }
        }

        private void bgCleanup() {
            // remove all which have been de-referenced by other than me. Garbagy but rare
            synchronized (cache) {
                cache.entrySet().removeIf(entry -> {
                    T value = entry.getValue();
                    int refCount = value.refCount();
                    if (refCount == 1) {
                        value.release(ReferenceCountedCache.this);
                    }
                    return refCount <= 1;
                });
            }
        }
    }
}

        try {
            if (value != null)
                value.release(this);
        } catch (Exception e) {
            Jvm.debug().on(getClass(), e);
        }
    
<methods>public static void assertCloseablesClosed() ,public final void close() ,public net.openhft.chronicle.core.StackTrace createdHere() ,public static void disableCloseableTracing() ,public static void enableCloseableTracing() ,public static void gcAndWaitForCloseablesToClose() ,public boolean isClosed() ,public boolean isClosing() ,public int referenceId() ,public void singleThreadedCheckDisabled(boolean) ,public void singleThreadedCheckReset() ,public void throwExceptionIfClosed() throws net.openhft.chronicle.core.io.ClosedIllegalStateException, net.openhft.chronicle.core.io.ThreadingIllegalStateException,public void throwExceptionIfClosedInSetter() throws net.openhft.chronicle.core.io.ClosedIllegalStateException, net.openhft.chronicle.core.io.ThreadingIllegalStateException,public java.lang.String toString() ,public static void unmonitor(net.openhft.chronicle.core.io.Closeable) ,public static boolean waitForCloseablesToClose(long) ,public void warnAndCloseIfNotClosed() <variables>private static final long CLOSED_OFFSET,protected static final boolean DISABLE_DISCARD_WARNING,private static final int STATE_CLOSED,private static final int STATE_CLOSING,private static final int STATE_NOT_CLOSED,protected static final long WARN_NS,private volatile transient int closed,protected volatile transient net.openhft.chronicle.core.StackTrace closedHere,private final transient net.openhft.chronicle.core.StackTrace createdHere,private final transient net.openhft.chronicle.core.io.AbstractCloseable.Finalizer finalizer,private int referenceId,private transient boolean singleThreadedCheckDisabled,private volatile transient java.lang.Thread usedByThread,private volatile transient net.openhft.chronicle.core.StackTrace usedByThreadHere