// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. package org.chromium.base; import androidx.annotation.Nullable; import java.util.Collections; import java.util.Set; import java.util.WeakHashMap; /** * A DiscardableReferencePool allows handing out typed references to objects ("payloads") that can * be dropped in one batch ("drained"), e.g. under memory pressure. In contrast to {@link * java.lang.ref.WeakReference}s, which drop their referents when they get garbage collected, a * reference pool gives more precise control over when exactly it is drained. * *

Internally it uses a {@link WeakHashMap} with the reference itself as a key to allow the * payloads to be garbage collected regularly when the last reference goes away before the pool is * drained. * *

This class and its references are not thread-safe and should not be used simultaneously by * multiple threads. */ public class DiscardableReferencePool { /** * The underlying data storage. The wildcard type parameter allows using a single pool for * references of any type. */ private final Set> mPool; public DiscardableReferencePool() { WeakHashMap, Boolean> map = new WeakHashMap<>(); mPool = Collections.newSetFromMap(map); } /** * A reference to an object in the pool. Will be nulled out when the pool is drained. * @param The type of the object. */ public static class DiscardableReference { @Nullable private T mPayload; private DiscardableReference(T payload) { assert payload != null; mPayload = payload; } /** * @return The referent, or null if the pool has been drained. */ @Nullable public T get() { return mPayload; } /** Clear the referent. */ private void discard() { assert mPayload != null; mPayload = null; } } /** * @param The type of the object. * @param payload The payload to add to the pool. * @return A new reference to the {@code payload}. */ public DiscardableReference put(T payload) { assert payload != null; DiscardableReference reference = new DiscardableReference<>(payload); mPool.add(reference); return reference; } /** * Remove this reference from the pool, allowing garbage collection to pick it up. * * @param ref The discardable reference to remove. */ public void remove(DiscardableReference ref) { assert ref != null; if (!mPool.contains(ref)) return; assert ref.get() != null; ref.discard(); mPool.remove(ref); } /** * Drains the pool, removing all references to objects in the pool and therefore allowing them * to be garbage collected. */ public void drain() { for (DiscardableReference ref : mPool) { ref.discard(); } mPool.clear(); } }