Reduce Object allocations in CompositeByteBuf.

Motivation:

We used subList in CompositeByteBuf to remove ranges of elements from the internal storage. Beside this we also used an foreach loop in a few cases which will crate an Iterator.

Modifications:

- Use our own sub-class of ArrayList which exposes removeRange(...). This allows to remove a range of elements without an extra allocation.
- Use an old style for loop to iterate over the elements to reduce object allocations.

Result:

Less allocations.
This commit is contained in:
Norman Maurer 2017-12-12 09:06:18 +01:00
parent 63bae0956a
commit 1988cd041d

View File

@ -48,7 +48,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
private final ByteBufAllocator alloc;
private final boolean direct;
private final List<Component> components;
private final ComponentList components;
private final int maxNumComponents;
private boolean freed;
@ -110,8 +110,8 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
setIndex(0, capacity());
}
private static List<Component> newList(int maxNumComponents) {
return new ArrayList<Component>(Math.min(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS, maxNumComponents));
private static ComponentList newList(int maxNumComponents) {
return new ComponentList(Math.min(AbstractByteBufAllocator.DEFAULT_MAX_COMPONENTS, maxNumComponents));
}
// Special constructor used by WrappedCompositeByteBuf
@ -120,7 +120,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
this.alloc = alloc;
direct = false;
maxNumComponents = 0;
components = Collections.emptyList();
components = null;
}
/**
@ -486,15 +486,16 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
if (numComponents == 0) {
return this;
}
List<Component> toRemove = components.subList(cIndex, cIndex + numComponents);
int endIndex = cIndex + numComponents;
boolean needsUpdate = false;
for (Component c: toRemove) {
for (int i = cIndex; i < endIndex; ++i) {
Component c = components.get(i);
if (c.length > 0) {
needsUpdate = true;
}
c.freeIfNecessary();
}
toRemove.clear();
components.removeRange(cIndex, endIndex);
if (needsUpdate) {
// Only need to call updateComponentOffsets if the length was > 0
@ -1557,7 +1558,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
c.freeIfNecessary();
}
components.subList(cIndex + 1, endCIndex).clear();
components.removeRange(cIndex + 1, endCIndex);
components.set(cIndex, new Component(consolidated));
updateComponentOffsets(cIndex);
return this;
@ -1576,8 +1577,9 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
// Discard everything if (readerIndex = writerIndex = capacity).
int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) {
c.freeIfNecessary();
int size = components.size();
for (int i = 0; i < size; i++) {
components.get(i).freeIfNecessary();
}
components.clear();
setIndex(0, 0);
@ -1590,7 +1592,7 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
for (int i = 0; i < firstComponentId; i ++) {
components.get(i).freeIfNecessary();
}
components.subList(0, firstComponentId).clear();
components.removeRange(0, firstComponentId);
// Update indexes and markers.
Component first = components.get(0);
@ -1612,8 +1614,9 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
// Discard everything if (readerIndex = writerIndex = capacity).
int writerIndex = writerIndex();
if (readerIndex == writerIndex && writerIndex == capacity()) {
for (Component c: components) {
c.freeIfNecessary();
int size = components.size();
for (int i = 0; i < size; i++) {
components.get(i).freeIfNecessary();
}
components.clear();
setIndex(0, 0);
@ -1626,19 +1629,20 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
for (int i = 0; i < firstComponentId; i ++) {
components.get(i).freeIfNecessary();
}
components.subList(0, firstComponentId).clear();
// Remove or replace the first readable component with a new slice.
Component c = components.get(0);
Component c = components.get(firstComponentId);
int adjustment = readerIndex - c.offset;
if (adjustment == c.length) {
// new slice would be empty, so remove instead
components.remove(0);
firstComponentId++;
} else {
Component newC = new Component(c.buf.slice(adjustment, c.length - adjustment));
components.set(0, newC);
components.set(firstComponentId, newC);
}
components.removeRange(0, firstComponentId);
// Update indexes and markers.
updateComponentOffsets(0);
setIndex(0, writerIndex - readerIndex);
@ -1972,4 +1976,17 @@ public class CompositeByteBuf extends AbstractReferenceCountedByteBuf implements
throw new UnsupportedOperationException("Read-Only");
}
}
private static final class ComponentList extends ArrayList<Component> {
ComponentList(int initialCapacity) {
super(initialCapacity);
}
// Expose this methods so we not need to create a new subList just to remove a range of elements.
@Override
public void removeRange(int fromIndex, int toIndex) {
super.removeRange(fromIndex, toIndex);
}
}
}