Repository: hbase Updated Branches: refs/heads/branch-2.1 5169cfc8c -> eb2725126
HBASE-21228 Memory leak since AbstractFSWAL caches Thread object and never clean later Project: http://git-wip-us.apache.org/repos/asf/hbase/repo Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/eb272512 Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/eb272512 Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/eb272512 Branch: refs/heads/branch-2.1 Commit: eb272512650a1926214ec37da1d4976a18228fb6 Parents: 5169cfc Author: Allan Yang <allan...@apache.org> Authored: Thu Sep 27 15:07:07 2018 +0800 Committer: Allan Yang <allan...@apache.org> Committed: Thu Sep 27 15:07:07 2018 +0800 ---------------------------------------------------------------------- .../hbase/regionserver/wal/AbstractFSWAL.java | 27 ++++++++------------ 1 file changed, 11 insertions(+), 16 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/hbase/blob/eb272512/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AbstractFSWAL.java ---------------------------------------------------------------------- diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AbstractFSWAL.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AbstractFSWAL.java index 9b31834..b493fd6 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AbstractFSWAL.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/wal/AbstractFSWAL.java @@ -34,8 +34,6 @@ import java.util.List; import java.util.Map; import java.util.OptionalLong; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -62,7 +60,6 @@ import org.apache.hadoop.hbase.log.HBaseMarkers; import org.apache.hadoop.hbase.regionserver.MultiVersionConcurrencyControl; import org.apache.hadoop.hbase.trace.TraceUtil; import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.CollectionUtils; import org.apache.hadoop.hbase.util.CommonFSUtils; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; import org.apache.hadoop.hbase.util.FSUtils; @@ -268,14 +265,11 @@ public abstract class AbstractFSWAL<W extends WriterBase> implements WAL { new ConcurrentSkipListMap<>(LOG_NAME_COMPARATOR); /** - * Map of {@link SyncFuture}s keyed by Handler objects. Used so we reuse SyncFutures. + * Map of {@link SyncFuture}s owned by Thread objects. Used so we reuse SyncFutures. + * Thread local is used so JVM can GC the terminated thread for us. See HBASE-21228 * <p> - * TODO: Reuse FSWALEntry's rather than create them anew each time as we do SyncFutures here. - * <p> - * TODO: Add a FSWalEntry and SyncFuture as thread locals on handlers rather than have them get - * them from this Map? */ - private final ConcurrentMap<Thread, SyncFuture> syncFuturesByHandler; + private final ThreadLocal<SyncFuture> cachedSyncFutures; /** * The class name of the runtime implementation, used as prefix for logging/tracing. @@ -429,9 +423,12 @@ public abstract class AbstractFSWAL<W extends WriterBase> implements WAL { .toNanos(conf.getInt("hbase.regionserver.hlog.slowsync.ms", DEFAULT_SLOW_SYNC_TIME_MS)); this.walSyncTimeoutNs = TimeUnit.MILLISECONDS .toNanos(conf.getLong("hbase.regionserver.hlog.sync.timeout", DEFAULT_WAL_SYNC_TIMEOUT_MS)); - int maxHandlersCount = conf.getInt(HConstants.REGION_SERVER_HANDLER_COUNT, 200); - // Presize our map of SyncFutures by handler objects. - this.syncFuturesByHandler = new ConcurrentHashMap<>(maxHandlersCount); + this.cachedSyncFutures = new ThreadLocal<SyncFuture>() { + @Override + protected SyncFuture initialValue() { + return new SyncFuture(); + } + }; this.implClassName = getClass().getSimpleName(); } @@ -723,7 +720,7 @@ public abstract class AbstractFSWAL<W extends WriterBase> implements WAL { // SyncFuture reuse by thread, if TimeoutIOException happens, ringbuffer // still refer to it, so if this thread use it next time may get a wrong // result. - this.syncFuturesByHandler.remove(Thread.currentThread()); + this.cachedSyncFutures.remove(); throw tioe; } catch (InterruptedException ie) { LOG.warn("Interrupted", ie); @@ -873,9 +870,7 @@ public abstract class AbstractFSWAL<W extends WriterBase> implements WAL { } protected final SyncFuture getSyncFuture(long sequence) { - return CollectionUtils - .computeIfAbsent(syncFuturesByHandler, Thread.currentThread(), SyncFuture::new) - .reset(sequence); + return cachedSyncFutures.get().reset(sequence); } protected final void requestLogRoll(boolean tooFewReplicas) {