From cb3819a6176a109689eb5f28a7143c17f71f2e8f Mon Sep 17 00:00:00 2001 From: amcreynolds Date: Mon, 6 Nov 2017 15:37:15 -0800 Subject: [PATCH] Optimize AbstractListenableFuture Memory Allocations Problem: If an empty ArrayList has addAll() invoked with a Collection argument that has a size less than 10, the underlying elementData Object[] is still grown to 10 via an Array copy. In the case of AbstractListenableFuture, the number of listeners is often 0 or 1, and AbstractListenableFuture is in the critical path, meaning this behavior causes unnecessary GC pressure for high throughput applications. Therefore, this commit enhances the logic to avoid the construction of the listener copy ArrayList and its iterator if possible, and if not, to use the more efficient constructor vs. addAll(). --- .../internal/AbstractListenableFuture.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/spy/memcached/internal/AbstractListenableFuture.java b/src/main/java/net/spy/memcached/internal/AbstractListenableFuture.java index fd0b4e970..23c54bdce 100644 --- a/src/main/java/net/spy/memcached/internal/AbstractListenableFuture.java +++ b/src/main/java/net/spy/memcached/internal/AbstractListenableFuture.java @@ -141,15 +141,22 @@ protected void notifyListeners() { * @param future the future to pass on to the listeners. */ protected void notifyListeners(final Future future) { - final List>> copy = - new ArrayList>>(); + final List>> copy; synchronized(this) { - copy.addAll(listeners); + if (listeners.isEmpty()) { + copy = null; + } + else { + copy = new ArrayList>>(listeners); + } listeners = new ArrayList>>(); } - for (GenericCompletionListener> listener - : copy) { - notifyListener(executor(), future, listener); + if (copy != null) { + for (GenericCompletionListener> listener + : copy) { + notifyListener(executor(), future, listener); + } } }