Add a reusable ArrayList to InternalThreadLocalMap
Motivation: See #3411. A reusable ArrayList in InternalThreadLocalMap can avoid allocations in the following pattern: ``` List<...> list = new ArrayList<...>(); add something to list but never use InternalThreadLocalMap return list.toArray(new ...[list.size()]); ``` Modifications: Add a reusable ArrayList to InternalThreadLocalMap and update codes to use it. Result: Reuse a thread local ArrayList to avoid allocations.
This commit is contained in:
parent
b354868dd8
commit
b7415a3307
@ -22,8 +22,8 @@ import static io.netty.handler.codec.http.cookie.CookieUtil.stripTrailingSeparat
|
||||
import static io.netty.handler.codec.http.cookie.CookieUtil.stripTrailingSeparatorOrNull;
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
@ -196,7 +196,7 @@ public final class ClientCookieEncoder extends CookieEncoder {
|
||||
if (!cookiesIt.hasNext()) {
|
||||
encode(buf, firstCookie);
|
||||
} else {
|
||||
List<Cookie> cookiesList = new ArrayList<Cookie>();
|
||||
List<Cookie> cookiesList = InternalThreadLocalMap.get().arrayList();
|
||||
cookiesList.add(firstCookie);
|
||||
while (cookiesIt.hasNext()) {
|
||||
cookiesList.add(cookiesIt.next());
|
||||
|
@ -30,6 +30,7 @@ import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.ErrorDataDec
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.MultiPartStatus;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder.NotEnoughDataDecoderException;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -1836,7 +1837,7 @@ public class HttpPostMultipartRequestDecoder implements InterfaceHttpPostRequest
|
||||
* @return an array of String where values that were separated by ';' or ','
|
||||
*/
|
||||
private static String[] splitMultipartHeaderValues(String svalue) {
|
||||
List<String> values = new ArrayList<String>(1);
|
||||
List<String> values = InternalThreadLocalMap.get().arrayList(1);
|
||||
boolean inQuote = false;
|
||||
boolean escapeNext = false;
|
||||
int start = 0;
|
||||
|
@ -17,13 +17,13 @@ package io.netty.util;
|
||||
|
||||
import io.netty.util.ByteProcessor.IndexOfProcessor;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -1050,7 +1050,7 @@ public final class AsciiString implements CharSequence, Comparable<CharSequence>
|
||||
* Splits the specified {@link String} with the specified delimiter..
|
||||
*/
|
||||
public AsciiString[] split(char delim) {
|
||||
final List<AsciiString> res = new ArrayList<AsciiString>();
|
||||
final List<AsciiString> res = InternalThreadLocalMap.get().arrayList();
|
||||
|
||||
int start = 0;
|
||||
final int length = length();
|
||||
|
@ -22,6 +22,7 @@ import io.netty.util.concurrent.FastThreadLocalThread;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Map;
|
||||
@ -34,6 +35,8 @@ import java.util.WeakHashMap;
|
||||
*/
|
||||
public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
|
||||
|
||||
private static final int DEFAULT_ARRAY_LIST_INITIAL_CAPACITY = 8;
|
||||
|
||||
public static final Object UNSET = new Object();
|
||||
|
||||
public static InternalThreadLocalMap getIfSet() {
|
||||
@ -160,6 +163,9 @@ public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap
|
||||
if (charsetDecoderCache != null) {
|
||||
count ++;
|
||||
}
|
||||
if (arrayList != null) {
|
||||
count ++;
|
||||
}
|
||||
|
||||
for (Object o: indexedVariables) {
|
||||
if (o != UNSET) {
|
||||
@ -198,6 +204,21 @@ public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap
|
||||
return cache;
|
||||
}
|
||||
|
||||
public <E> ArrayList<E> arrayList() {
|
||||
return arrayList(DEFAULT_ARRAY_LIST_INITIAL_CAPACITY);
|
||||
}
|
||||
|
||||
public <E> ArrayList<E> arrayList(int minCapacity) {
|
||||
ArrayList<E> list = (ArrayList<E>) arrayList;
|
||||
if (list == null) {
|
||||
list = (ArrayList<E>) new ArrayList<Object>(minCapacity);
|
||||
} else {
|
||||
list.clear();
|
||||
list.ensureCapacity(minCapacity);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public int futureListenerStackDepth() {
|
||||
return futureListenerStackDepth;
|
||||
}
|
||||
|
@ -16,7 +16,6 @@
|
||||
package io.netty.util.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Formatter;
|
||||
import java.util.List;
|
||||
|
||||
@ -94,7 +93,7 @@ public final class StringUtil {
|
||||
*/
|
||||
public static String[] split(String value, char delim) {
|
||||
final int end = value.length();
|
||||
final List<String> res = new ArrayList<String>();
|
||||
final List<String> res = InternalThreadLocalMap.get().arrayList();
|
||||
|
||||
int start = 0;
|
||||
for (int i = 0; i < end; i ++) {
|
||||
@ -136,7 +135,7 @@ public final class StringUtil {
|
||||
*/
|
||||
public static String[] split(String value, char delim, int maxParts) {
|
||||
final int end = value.length();
|
||||
final List<String> res = new ArrayList<String>();
|
||||
final List<String> res = InternalThreadLocalMap.get().arrayList();
|
||||
|
||||
int start = 0;
|
||||
int cpt = 1;
|
||||
|
@ -21,6 +21,7 @@ import io.netty.util.concurrent.FastThreadLocal;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.CharsetDecoder;
|
||||
import java.nio.charset.CharsetEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@ -51,6 +52,9 @@ class UnpaddedInternalThreadLocalMap {
|
||||
Map<Charset, CharsetEncoder> charsetEncoderCache;
|
||||
Map<Charset, CharsetDecoder> charsetDecoderCache;
|
||||
|
||||
// ArrayList-related thread-locals
|
||||
ArrayList<Object> arrayList;
|
||||
|
||||
UnpaddedInternalThreadLocalMap(Object[] indexedVariables) {
|
||||
this.indexedVariables = indexedVariables;
|
||||
}
|
||||
|
@ -15,7 +15,8 @@
|
||||
*/
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@ -33,7 +34,7 @@ public final class IdentityCipherSuiteFilter implements CipherSuiteFilter {
|
||||
if (ciphers == null) {
|
||||
return defaultCiphers.toArray(new String[defaultCiphers.size()]);
|
||||
} else {
|
||||
List<String> newCiphers = new ArrayList<String>(supportedCiphers.size());
|
||||
List<String> newCiphers = InternalThreadLocalMap.get().arrayList(supportedCiphers.size());
|
||||
for (String c : ciphers) {
|
||||
if (c == null) {
|
||||
break;
|
||||
|
@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufAllocator;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
@ -42,7 +43,6 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.ReadOnlyBufferException;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@ -1018,7 +1018,7 @@ public final class OpenSslEngine extends SSLEngine {
|
||||
|
||||
@Override
|
||||
public String[] getEnabledProtocols() {
|
||||
List<String> enabled = new ArrayList<String>();
|
||||
List<String> enabled = InternalThreadLocalMap.get().arrayList();
|
||||
// Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled
|
||||
enabled.add(PROTOCOL_SSL_V2_HELLO);
|
||||
|
||||
|
@ -15,8 +15,9 @@
|
||||
*/
|
||||
package io.netty.handler.ssl;
|
||||
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@ -40,10 +41,10 @@ public final class SupportedCipherSuiteFilter implements CipherSuiteFilter {
|
||||
|
||||
final List<String> newCiphers;
|
||||
if (ciphers == null) {
|
||||
newCiphers = new ArrayList<String>(defaultCiphers.size());
|
||||
newCiphers = InternalThreadLocalMap.get().arrayList(defaultCiphers.size());
|
||||
ciphers = defaultCiphers;
|
||||
} else {
|
||||
newCiphers = new ArrayList<String>(supportedCiphers.size());
|
||||
newCiphers = InternalThreadLocalMap.get().arrayList(supportedCiphers.size());
|
||||
}
|
||||
for (String c : ciphers) {
|
||||
if (c == null) {
|
||||
|
@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.util.internal.EmptyArrays;
|
||||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
|
||||
import javax.net.ssl.ManagerFactoryParameters;
|
||||
import javax.net.ssl.TrustManager;
|
||||
@ -31,7 +32,6 @@ import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
@ -151,7 +151,7 @@ public final class FingerprintTrustManagerFactory extends SimpleTrustManagerFact
|
||||
throw new NullPointerException("fingerprints");
|
||||
}
|
||||
|
||||
List<byte[]> list = new ArrayList<byte[]>();
|
||||
List<byte[]> list = InternalThreadLocalMap.get().arrayList();
|
||||
for (byte[] f: fingerprints) {
|
||||
if (f == null) {
|
||||
break;
|
||||
@ -171,7 +171,7 @@ public final class FingerprintTrustManagerFactory extends SimpleTrustManagerFact
|
||||
throw new NullPointerException("fingerprints");
|
||||
}
|
||||
|
||||
List<byte[]> list = new ArrayList<byte[]>();
|
||||
List<byte[]> list = InternalThreadLocalMap.get().arrayList();
|
||||
for (String f: fingerprints) {
|
||||
if (f == null) {
|
||||
break;
|
||||
|
@ -23,9 +23,9 @@ import io.netty.channel.ReflectiveChannelFactory;
|
||||
import io.netty.channel.socket.DatagramChannel;
|
||||
import io.netty.channel.socket.InternetProtocolFamily;
|
||||
import io.netty.resolver.HostsFileEntriesResolver;
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||
@ -170,7 +170,7 @@ public final class DnsNameResolverBuilder {
|
||||
checkNotNull(resolvedAddressTypes, "resolvedAddressTypes");
|
||||
|
||||
final List<InternetProtocolFamily> list =
|
||||
new ArrayList<InternetProtocolFamily>(InternetProtocolFamily.values().length);
|
||||
InternalThreadLocalMap.get().arrayList(InternetProtocolFamily.values().length);
|
||||
|
||||
for (InternetProtocolFamily f : resolvedAddressTypes) {
|
||||
if (f == null) {
|
||||
@ -207,7 +207,7 @@ public final class DnsNameResolverBuilder {
|
||||
checkNotNull(resolvedAddressTypes, "resolveAddressTypes");
|
||||
|
||||
final List<InternetProtocolFamily> list =
|
||||
new ArrayList<InternetProtocolFamily>(InternetProtocolFamily.values().length);
|
||||
InternalThreadLocalMap.get().arrayList(InternetProtocolFamily.values().length);
|
||||
|
||||
for (InternetProtocolFamily f : resolvedAddressTypes) {
|
||||
if (f == null) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package io.netty.resolver.dns;
|
||||
|
||||
import io.netty.util.internal.InternalThreadLocalMap;
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
|
||||
@ -241,7 +242,7 @@ public abstract class DnsServerAddresses {
|
||||
throw new NullPointerException("addresses");
|
||||
}
|
||||
|
||||
List<InetSocketAddress> list = new ArrayList<InetSocketAddress>(addresses.length);
|
||||
List<InetSocketAddress> list = InternalThreadLocalMap.get().arrayList(addresses.length);
|
||||
for (InetSocketAddress a: addresses) {
|
||||
if (a == null) {
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user