Avoid object allocations for HTTP2 child streams.

Motivation:

We are allocating a hash map for every HTTP2 Stream to store it's children.
Most streams are leafs in the priority tree and don't have children.

Modification:

 - Only allocate children when we actually use them.
 - Make EmptyIntObjectMap not throw a UnsupportedOperationException on remove, but return null instead (as is stated in it's javadoc).

Result:

Fewer unnecessary allocations.
This commit is contained in:
Jakob Buchgraber 2015-04-03 10:51:29 -07:00 committed by Scott Mitchell
parent 330bc39d91
commit e40c27d9ed
2 changed files with 13 additions and 7 deletions

View File

@ -38,6 +38,7 @@ import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http2.Http2StreamRemovalPolicy.Action; import io.netty.handler.codec.http2.Http2StreamRemovalPolicy.Action;
import io.netty.util.collection.IntObjectHashMap; import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap; import io.netty.util.collection.IntObjectMap;
import io.netty.util.collection.PrimitiveCollections;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -216,7 +217,7 @@ public class DefaultHttp2Connection implements Http2Connection {
private State state = IDLE; private State state = IDLE;
private short weight = DEFAULT_PRIORITY_WEIGHT; private short weight = DEFAULT_PRIORITY_WEIGHT;
private DefaultStream parent; private DefaultStream parent;
private IntObjectMap<DefaultStream> children = newChildMap(); private IntObjectMap<DefaultStream> children = PrimitiveCollections.emptyIntObjectMap();
private int totalChildWeights; private int totalChildWeights;
private int prioritizableForTree = 1; private int prioritizableForTree = 1;
private boolean resetSent; private boolean resetSent;
@ -503,6 +504,12 @@ public class DefaultHttp2Connection implements Http2Connection {
} }
} }
private void initChildrenIfEmpty() {
if (children == PrimitiveCollections.<DefaultStream>emptyIntObjectMap()) {
children = new IntObjectHashMap<DefaultStream>(4);
}
}
@Override @Override
public final boolean remoteSideOpen() { public final boolean remoteSideOpen() {
return state == HALF_CLOSED_LOCAL || state == OPEN || state == RESERVED_REMOTE; return state == HALF_CLOSED_LOCAL || state == OPEN || state == RESERVED_REMOTE;
@ -539,7 +546,7 @@ public class DefaultHttp2Connection implements Http2Connection {
totalChildWeights = 0; totalChildWeights = 0;
prioritizableForTree = isPrioritizable() ? 1 : 0; prioritizableForTree = isPrioritizable() ? 1 : 0;
IntObjectMap<DefaultStream> prevChildren = children; IntObjectMap<DefaultStream> prevChildren = children;
children = newChildMap(); children = PrimitiveCollections.emptyIntObjectMap();
return prevChildren; return prevChildren;
} }
@ -561,6 +568,9 @@ public class DefaultHttp2Connection implements Http2Connection {
} }
} }
// Lazily initialize the children to save object allocations.
initChildrenIfEmpty();
if (children.put(child.id(), child) == null) { if (children.put(child.id(), child) == null) {
totalChildWeights += child.weight(); totalChildWeights += child.weight();
incrementPrioritizableForTree(child.prioritizableForTree(), oldParent); incrementPrioritizableForTree(child.prioritizableForTree(), oldParent);
@ -673,10 +683,6 @@ public class DefaultHttp2Connection implements Http2Connection {
} }
} }
private static IntObjectMap<DefaultStream> newChildMap() {
return new IntObjectHashMap<DefaultStream>(4);
}
/** /**
* Allows a correlation to be made between a stream and its old parent before a parent change occurs * Allows a correlation to be made between a stream and its old parent before a parent change occurs
*/ */

View File

@ -68,7 +68,7 @@ public final class PrimitiveCollections {
@Override @Override
public Object remove(int key) { public Object remove(int key) {
throw new UnsupportedOperationException("remove"); return null;
} }
@Override @Override