Allow to obtain informations of used direct and heap memory for ByteBufAllocator implementations
Motivation: Often its useful for the user to be able to get some stats about the memory allocated via an allocator. Modifications: - Allow to obtain the used heap and direct memory for an allocator - Add test case Result: Fixes [#6341]
This commit is contained in:
parent
93f5f62a20
commit
461f9a1212
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link ByteBufAllocator} which exposes metrics.
|
||||||
|
*/
|
||||||
|
public interface InstrumentedByteBufAllocator extends ByteBufAllocator {
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes of heap memory used by a {@link ByteBufAllocator} or {@code -1} if unknown.
|
||||||
|
*/
|
||||||
|
long usedHeapMemory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of bytes of direct memory used by a {@link ByteBufAllocator} or {@code -1} if unknown.
|
||||||
|
*/
|
||||||
|
long usedDirectMemory();
|
||||||
|
}
|
@ -29,7 +29,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
public class PooledByteBufAllocator extends AbstractByteBufAllocator implements InstrumentedByteBufAllocator {
|
||||||
|
|
||||||
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
|
||||||
private static final int DEFAULT_NUM_HEAP_ARENA;
|
private static final int DEFAULT_NUM_HEAP_ARENA;
|
||||||
@ -184,9 +184,9 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public PooledByteBufAllocator(boolean preferDirect, int nHeapArena,
|
public PooledByteBufAllocator(boolean preferDirect, int nHeapArena,
|
||||||
int nDirectArena, int pageSize, int maxOrder, int tinyCacheSize,
|
int nDirectArena, int pageSize, int maxOrder, int tinyCacheSize,
|
||||||
int smallCacheSize, int normalCacheSize,
|
int smallCacheSize, int normalCacheSize,
|
||||||
boolean useCacheForAllThreads) {
|
boolean useCacheForAllThreads) {
|
||||||
this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
|
this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
|
||||||
tinyCacheSize, smallCacheSize, normalCacheSize,
|
tinyCacheSize, smallCacheSize, normalCacheSize,
|
||||||
useCacheForAllThreads, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
|
useCacheForAllThreads, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
|
||||||
@ -519,6 +519,30 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
|
|||||||
return chunkSize;
|
return chunkSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final long usedHeapMemory() {
|
||||||
|
return usedMemory(heapArenas);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final long usedDirectMemory() {
|
||||||
|
return usedMemory(directArenas);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long usedMemory(PoolArena<?>... arenas) {
|
||||||
|
if (arenas == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
long used = 0;
|
||||||
|
for (PoolArena<?> arena : arenas) {
|
||||||
|
used += arena.numActiveBytes();
|
||||||
|
if (used < 0) {
|
||||||
|
return Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return used;
|
||||||
|
}
|
||||||
|
|
||||||
final PoolThreadCache threadCache() {
|
final PoolThreadCache threadCache() {
|
||||||
return threadCache.get();
|
return threadCache.get();
|
||||||
}
|
}
|
||||||
|
@ -15,13 +15,18 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
|
import io.netty.util.internal.LongCounter;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simplistic {@link ByteBufAllocator} implementation that does not pool anything.
|
* Simplistic {@link ByteBufAllocator} implementation that does not pool anything.
|
||||||
*/
|
*/
|
||||||
public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
|
public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator implements InstrumentedByteBufAllocator {
|
||||||
|
|
||||||
|
private final LongCounter directCounter = PlatformDependent.newLongCounter();
|
||||||
|
private final LongCounter heapCounter = PlatformDependent.newLongCounter();
|
||||||
private final boolean disableLeakDetector;
|
private final boolean disableLeakDetector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,16 +61,21 @@ public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
|
protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
|
||||||
return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
|
return PlatformDependent.hasUnsafe() ?
|
||||||
: new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
|
new InstrumentedUnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
|
||||||
|
new InstrumentedUnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
|
||||||
ByteBuf buf = PlatformDependent.hasUnsafe() ?
|
final ByteBuf buf;
|
||||||
UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
|
if (PlatformDependent.hasUnsafe()) {
|
||||||
new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
buf = PlatformDependent.useDirectBufferNoCleaner() ?
|
||||||
|
new InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(this, initialCapacity, maxCapacity) :
|
||||||
|
new InstrumentedUnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||||
|
} else {
|
||||||
|
buf = new InstrumentedUnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
|
||||||
|
}
|
||||||
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
|
return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,4 +95,126 @@ public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {
|
|||||||
public boolean isDirectBufferPooled() {
|
public boolean isDirectBufferPooled() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long usedHeapMemory() {
|
||||||
|
return heapCounter.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long usedDirectMemory() {
|
||||||
|
return directCounter.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class InstrumentedUnpooledUnsafeHeapByteBuf extends UnpooledUnsafeHeapByteBuf {
|
||||||
|
InstrumentedUnpooledUnsafeHeapByteBuf(UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
|
super(alloc, initialCapacity, maxCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
byte[] allocateArray(int initialCapacity) {
|
||||||
|
byte[] bytes = super.allocateArray(initialCapacity);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).heapCounter.add(bytes.length);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void freeArray(byte[] array) {
|
||||||
|
int length = array.length;
|
||||||
|
super.freeArray(array);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).heapCounter.add(-length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class InstrumentedUnpooledHeapByteBuf extends UnpooledHeapByteBuf {
|
||||||
|
InstrumentedUnpooledHeapByteBuf(UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
|
super(alloc, initialCapacity, maxCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
byte[] allocateArray(int initialCapacity) {
|
||||||
|
byte[] bytes = super.allocateArray(initialCapacity);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).heapCounter.add(bytes.length);
|
||||||
|
return bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void freeArray(byte[] array) {
|
||||||
|
int length = array.length;
|
||||||
|
super.freeArray(array);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).heapCounter.add(-length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf
|
||||||
|
extends UnpooledUnsafeNoCleanerDirectByteBuf {
|
||||||
|
InstrumentedUnpooledUnsafeNoCleanerDirectByteBuf(
|
||||||
|
UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
|
super(alloc, initialCapacity, maxCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuffer allocateDirect(int initialCapacity) {
|
||||||
|
ByteBuffer buffer = super.allocateDirect(initialCapacity);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(buffer.capacity());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
ByteBuffer reallocateDirect(ByteBuffer oldBuffer, int initialCapacity) {
|
||||||
|
int capacity = oldBuffer.capacity();
|
||||||
|
ByteBuffer buffer = super.reallocateDirect(oldBuffer, initialCapacity);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(buffer.capacity() - capacity);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void freeDirect(ByteBuffer buffer) {
|
||||||
|
int capacity = buffer.capacity();
|
||||||
|
super.freeDirect(buffer);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(-capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class InstrumentedUnpooledUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
|
||||||
|
InstrumentedUnpooledUnsafeDirectByteBuf(
|
||||||
|
UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
|
super(alloc, initialCapacity, maxCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuffer allocateDirect(int initialCapacity) {
|
||||||
|
ByteBuffer buffer = super.allocateDirect(initialCapacity);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(buffer.capacity());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void freeDirect(ByteBuffer buffer) {
|
||||||
|
int capacity = buffer.capacity();
|
||||||
|
super.freeDirect(buffer);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(-capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class InstrumentedUnpooledDirectByteBuf extends UnpooledDirectByteBuf {
|
||||||
|
InstrumentedUnpooledDirectByteBuf(
|
||||||
|
UnpooledByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
|
super(alloc, initialCapacity, maxCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ByteBuffer allocateDirect(int initialCapacity) {
|
||||||
|
ByteBuffer buffer = super.allocateDirect(initialCapacity);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(buffer.capacity());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void freeDirect(ByteBuffer buffer) {
|
||||||
|
int capacity = buffer.capacity();
|
||||||
|
super.freeDirect(buffer);
|
||||||
|
((UnpooledByteBufAllocator) alloc()).directCounter.add(-capacity);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ import java.nio.channels.FileChannel;
|
|||||||
import java.nio.channels.GatheringByteChannel;
|
import java.nio.channels.GatheringByteChannel;
|
||||||
import java.nio.channels.ScatteringByteChannel;
|
import java.nio.channels.ScatteringByteChannel;
|
||||||
|
|
||||||
|
import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Big endian Java heap buffer implementation.
|
* Big endian Java heap buffer implementation.
|
||||||
*/
|
*/
|
||||||
@ -43,7 +45,18 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
* @param maxCapacity the max capacity of the underlying byte array
|
* @param maxCapacity the max capacity of the underlying byte array
|
||||||
*/
|
*/
|
||||||
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
this(alloc, new byte[initialCapacity], 0, 0, maxCapacity);
|
super(maxCapacity);
|
||||||
|
|
||||||
|
checkNotNull(alloc, "alloc");
|
||||||
|
|
||||||
|
if (initialCapacity > maxCapacity) {
|
||||||
|
throw new IllegalArgumentException(String.format(
|
||||||
|
"initialCapacity(%d) > maxCapacity(%d)", initialCapacity, maxCapacity));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.alloc = alloc;
|
||||||
|
setArray(allocateArray(initialCapacity));
|
||||||
|
setIndex(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,20 +66,11 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
* @param maxCapacity the max capacity of the underlying byte array
|
* @param maxCapacity the max capacity of the underlying byte array
|
||||||
*/
|
*/
|
||||||
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
|
protected UnpooledHeapByteBuf(ByteBufAllocator alloc, byte[] initialArray, int maxCapacity) {
|
||||||
this(alloc, initialArray, 0, initialArray.length, maxCapacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnpooledHeapByteBuf(
|
|
||||||
ByteBufAllocator alloc, byte[] initialArray, int readerIndex, int writerIndex, int maxCapacity) {
|
|
||||||
|
|
||||||
super(maxCapacity);
|
super(maxCapacity);
|
||||||
|
|
||||||
if (alloc == null) {
|
checkNotNull(alloc, "alloc");
|
||||||
throw new NullPointerException("alloc");
|
checkNotNull(initialArray, "initialArray");
|
||||||
}
|
|
||||||
if (initialArray == null) {
|
|
||||||
throw new NullPointerException("initialArray");
|
|
||||||
}
|
|
||||||
if (initialArray.length > maxCapacity) {
|
if (initialArray.length > maxCapacity) {
|
||||||
throw new IllegalArgumentException(String.format(
|
throw new IllegalArgumentException(String.format(
|
||||||
"initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
|
"initialCapacity(%d) > maxCapacity(%d)", initialArray.length, maxCapacity));
|
||||||
@ -74,7 +78,15 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
this.alloc = alloc;
|
this.alloc = alloc;
|
||||||
setArray(initialArray);
|
setArray(initialArray);
|
||||||
setIndex(readerIndex, writerIndex);
|
setIndex(0, initialArray.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] allocateArray(int initialCapacity) {
|
||||||
|
return new byte[initialCapacity];
|
||||||
|
}
|
||||||
|
|
||||||
|
void freeArray(byte[] array) {
|
||||||
|
// NOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setArray(byte[] initialArray) {
|
private void setArray(byte[] initialArray) {
|
||||||
@ -108,23 +120,26 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
checkNewCapacity(newCapacity);
|
checkNewCapacity(newCapacity);
|
||||||
|
|
||||||
int oldCapacity = array.length;
|
int oldCapacity = array.length;
|
||||||
|
byte[] oldArray = array;
|
||||||
if (newCapacity > oldCapacity) {
|
if (newCapacity > oldCapacity) {
|
||||||
byte[] newArray = new byte[newCapacity];
|
byte[] newArray = allocateArray(newCapacity);
|
||||||
System.arraycopy(array, 0, newArray, 0, array.length);
|
System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
|
||||||
setArray(newArray);
|
setArray(newArray);
|
||||||
|
freeArray(oldArray);
|
||||||
} else if (newCapacity < oldCapacity) {
|
} else if (newCapacity < oldCapacity) {
|
||||||
byte[] newArray = new byte[newCapacity];
|
byte[] newArray = allocateArray(newCapacity);
|
||||||
int readerIndex = readerIndex();
|
int readerIndex = readerIndex();
|
||||||
if (readerIndex < newCapacity) {
|
if (readerIndex < newCapacity) {
|
||||||
int writerIndex = writerIndex();
|
int writerIndex = writerIndex();
|
||||||
if (writerIndex > newCapacity) {
|
if (writerIndex > newCapacity) {
|
||||||
writerIndex(writerIndex = newCapacity);
|
writerIndex(writerIndex = newCapacity);
|
||||||
}
|
}
|
||||||
System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
|
System.arraycopy(oldArray, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
|
||||||
} else {
|
} else {
|
||||||
setIndex(newCapacity, newCapacity);
|
setIndex(newCapacity, newCapacity);
|
||||||
}
|
}
|
||||||
setArray(newArray);
|
setArray(newArray);
|
||||||
|
freeArray(oldArray);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -534,6 +549,7 @@ public class UnpooledHeapByteBuf extends AbstractReferenceCountedByteBuf {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deallocate() {
|
protected void deallocate() {
|
||||||
|
freeArray(array);
|
||||||
array = null;
|
array = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ package io.netty.buffer;
|
|||||||
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
|
||||||
final class UnpooledUnsafeHeapByteBuf extends UnpooledHeapByteBuf {
|
class UnpooledUnsafeHeapByteBuf extends UnpooledHeapByteBuf {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new heap buffer with a newly allocated byte array.
|
* Creates a new heap buffer with a newly allocated byte array.
|
||||||
|
@ -19,7 +19,7 @@ import io.netty.util.internal.PlatformDependent;
|
|||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
final class UnpooledUnsafeNoCleanerDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
|
class UnpooledUnsafeNoCleanerDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
|
||||||
|
|
||||||
UnpooledUnsafeNoCleanerDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
UnpooledUnsafeNoCleanerDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
|
||||||
super(alloc, initialCapacity, maxCapacity);
|
super(alloc, initialCapacity, maxCapacity);
|
||||||
@ -30,6 +30,10 @@ final class UnpooledUnsafeNoCleanerDirectByteBuf extends UnpooledUnsafeDirectByt
|
|||||||
return PlatformDependent.allocateDirectNoCleaner(initialCapacity);
|
return PlatformDependent.allocateDirectNoCleaner(initialCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteBuffer reallocateDirect(ByteBuffer oldBuffer, int initialCapacity) {
|
||||||
|
return PlatformDependent.reallocateDirectNoCleaner(oldBuffer, initialCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void freeDirect(ByteBuffer buffer) {
|
protected void freeDirect(ByteBuffer buffer) {
|
||||||
PlatformDependent.freeDirectNoCleaner(buffer);
|
PlatformDependent.freeDirectNoCleaner(buffer);
|
||||||
@ -45,7 +49,7 @@ final class UnpooledUnsafeNoCleanerDirectByteBuf extends UnpooledUnsafeDirectByt
|
|||||||
|
|
||||||
if (newCapacity > oldCapacity) {
|
if (newCapacity > oldCapacity) {
|
||||||
ByteBuffer oldBuffer = buffer;
|
ByteBuffer oldBuffer = buffer;
|
||||||
ByteBuffer newBuffer = PlatformDependent.reallocateDirectNoCleaner(oldBuffer, newCapacity);
|
ByteBuffer newBuffer = reallocateDirect(oldBuffer, newCapacity);
|
||||||
setByteBuffer(newBuffer, false);
|
setByteBuffer(newBuffer, false);
|
||||||
} else if (newCapacity < oldCapacity) {
|
} else if (newCapacity < oldCapacity) {
|
||||||
ByteBuffer oldBuffer = buffer;
|
ByteBuffer oldBuffer = buffer;
|
||||||
|
@ -16,18 +16,19 @@
|
|||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
|
import org.junit.Assume;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
public abstract class AbstractByteBufAllocatorTest extends ByteBufAllocatorTest {
|
public abstract class AbstractByteBufAllocatorTest<T extends AbstractByteBufAllocator> extends ByteBufAllocatorTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected abstract AbstractByteBufAllocator newAllocator(boolean preferDirect);
|
protected abstract T newAllocator(boolean preferDirect);
|
||||||
|
|
||||||
protected abstract AbstractByteBufAllocator newUnpooledAllocator();
|
protected abstract T newUnpooledAllocator();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isDirectExpected(boolean preferDirect) {
|
protected boolean isDirectExpected(boolean preferDirect) {
|
||||||
@ -51,7 +52,7 @@ public abstract class AbstractByteBufAllocatorTest extends ByteBufAllocatorTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void testCalculateNewCapacity(boolean preferDirect) {
|
private void testCalculateNewCapacity(boolean preferDirect) {
|
||||||
ByteBufAllocator allocator = newAllocator(preferDirect);
|
T allocator = newAllocator(preferDirect);
|
||||||
assertEquals(8, allocator.calculateNewCapacity(1, 8));
|
assertEquals(8, allocator.calculateNewCapacity(1, 8));
|
||||||
assertEquals(7, allocator.calculateNewCapacity(1, 7));
|
assertEquals(7, allocator.calculateNewCapacity(1, 7));
|
||||||
assertEquals(64, allocator.calculateNewCapacity(1, 129));
|
assertEquals(64, allocator.calculateNewCapacity(1, 129));
|
||||||
@ -78,7 +79,7 @@ public abstract class AbstractByteBufAllocatorTest extends ByteBufAllocatorTest
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnsafeHeapBufferAndUnsafeDirectBuffer() {
|
public void testUnsafeHeapBufferAndUnsafeDirectBuffer() {
|
||||||
AbstractByteBufAllocator allocator = newUnpooledAllocator();
|
T allocator = newUnpooledAllocator();
|
||||||
ByteBuf directBuffer = allocator.directBuffer();
|
ByteBuf directBuffer = allocator.directBuffer();
|
||||||
assertInstanceOf(directBuffer,
|
assertInstanceOf(directBuffer,
|
||||||
PlatformDependent.hasUnsafe() ? UnpooledUnsafeDirectByteBuf.class : UnpooledDirectByteBuf.class);
|
PlatformDependent.hasUnsafe() ? UnpooledUnsafeDirectByteBuf.class : UnpooledDirectByteBuf.class);
|
||||||
@ -94,4 +95,50 @@ public abstract class AbstractByteBufAllocatorTest extends ByteBufAllocatorTest
|
|||||||
// Unwrap if needed
|
// Unwrap if needed
|
||||||
assertTrue(clazz.isInstance(buffer instanceof SimpleLeakAwareByteBuf ? buffer.unwrap() : buffer));
|
assertTrue(clazz.isInstance(buffer instanceof SimpleLeakAwareByteBuf ? buffer.unwrap() : buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
public void testUsedDirectMemory() {
|
||||||
|
InstrumentedByteBufAllocator allocator = (InstrumentedByteBufAllocator) newAllocator(true);
|
||||||
|
assertEquals(0, allocator.usedDirectMemory());
|
||||||
|
ByteBuf buffer = allocator.directBuffer(1024, 4096);
|
||||||
|
int capacity = buffer.capacity();
|
||||||
|
assertEquals(expectedUsedMemory((T) allocator, capacity), allocator.usedDirectMemory());
|
||||||
|
|
||||||
|
// Double the size of the buffer
|
||||||
|
buffer.capacity(capacity << 1);
|
||||||
|
capacity = buffer.capacity();
|
||||||
|
assertEquals(buffer.toString(), expectedUsedMemory((T) allocator, capacity), allocator.usedDirectMemory());
|
||||||
|
|
||||||
|
buffer.release();
|
||||||
|
assertEquals(expectedUsedMemoryAfterRelease((T) allocator, capacity), allocator.usedDirectMemory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
public void testUsedHeapMemory() {
|
||||||
|
InstrumentedByteBufAllocator allocator = (InstrumentedByteBufAllocator) newAllocator(true);
|
||||||
|
Assume.assumeTrue(allocator instanceof InstrumentedByteBufAllocator);
|
||||||
|
|
||||||
|
assertEquals(0, allocator.usedHeapMemory());
|
||||||
|
ByteBuf buffer = allocator.heapBuffer(1024, 4096);
|
||||||
|
int capacity = buffer.capacity();
|
||||||
|
assertEquals(expectedUsedMemory((T) allocator, capacity), allocator.usedHeapMemory());
|
||||||
|
|
||||||
|
// Double the size of the buffer
|
||||||
|
buffer.capacity(capacity << 1);
|
||||||
|
capacity = buffer.capacity();
|
||||||
|
assertEquals(expectedUsedMemory((T) allocator, capacity), allocator.usedHeapMemory());
|
||||||
|
|
||||||
|
buffer.release();
|
||||||
|
assertEquals(expectedUsedMemoryAfterRelease((T) allocator, capacity), allocator.usedHeapMemory());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long expectedUsedMemory(T allocator, int capacity) {
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected long expectedUsedMemoryAfterRelease(T allocator, int capacity) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,21 +38,34 @@ import static org.junit.Assert.assertFalse;
|
|||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class PooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest {
|
public class PooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest<PooledByteBufAllocator> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractByteBufAllocator newAllocator(boolean preferDirect) {
|
protected PooledByteBufAllocator newAllocator(boolean preferDirect) {
|
||||||
return new PooledByteBufAllocator(preferDirect);
|
return new PooledByteBufAllocator(preferDirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractByteBufAllocator newUnpooledAllocator() {
|
protected PooledByteBufAllocator newUnpooledAllocator() {
|
||||||
return new PooledByteBufAllocator(0, 0, 8192, 1);
|
return new PooledByteBufAllocator(0, 0, 8192, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long expectedUsedMemory(PooledByteBufAllocator allocator, int capacity) {
|
||||||
|
return allocator.chunkSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected long expectedUsedMemoryAfterRelease(PooledByteBufAllocator allocator, int capacity) {
|
||||||
|
// This is the case as allocations will start in qInit and chunks in qInit will never be released until
|
||||||
|
// these are moved to q000.
|
||||||
|
// See https://www.bsdcan.org/2006/papers/jemalloc.pdf
|
||||||
|
return allocator.chunkSize();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPooledUnsafeHeapBufferAndUnsafeDirectBuffer() {
|
public void testPooledUnsafeHeapBufferAndUnsafeDirectBuffer() {
|
||||||
AbstractByteBufAllocator allocator = newAllocator(true);
|
PooledByteBufAllocator allocator = newAllocator(true);
|
||||||
ByteBuf directBuffer = allocator.directBuffer();
|
ByteBuf directBuffer = allocator.directBuffer();
|
||||||
assertInstanceOf(directBuffer,
|
assertInstanceOf(directBuffer,
|
||||||
PlatformDependent.hasUnsafe() ? PooledUnsafeDirectByteBuf.class : PooledDirectByteBuf.class);
|
PlatformDependent.hasUnsafe() ? PooledUnsafeDirectByteBuf.class : PooledDirectByteBuf.class);
|
||||||
|
@ -15,15 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
public class UnpooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest {
|
public class UnpooledByteBufAllocatorTest extends AbstractByteBufAllocatorTest<UnpooledByteBufAllocator> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractByteBufAllocator newAllocator(boolean preferDirect) {
|
protected UnpooledByteBufAllocator newAllocator(boolean preferDirect) {
|
||||||
return new UnpooledByteBufAllocator(preferDirect);
|
return new UnpooledByteBufAllocator(preferDirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AbstractByteBufAllocator newUnpooledAllocator() {
|
protected UnpooledByteBufAllocator newUnpooledAllocator() {
|
||||||
return new UnpooledByteBufAllocator(false);
|
return new UnpooledByteBufAllocator(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.microbench.buffer;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBufAllocator;
|
||||||
|
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||||
|
import io.netty.microbench.util.AbstractMicrobenchmark;
|
||||||
|
import org.openjdk.jmh.annotations.Benchmark;
|
||||||
|
import org.openjdk.jmh.annotations.Measurement;
|
||||||
|
import org.openjdk.jmh.annotations.Param;
|
||||||
|
import org.openjdk.jmh.annotations.Scope;
|
||||||
|
import org.openjdk.jmh.annotations.State;
|
||||||
|
import org.openjdk.jmh.annotations.Threads;
|
||||||
|
import org.openjdk.jmh.annotations.Warmup;
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@Warmup(iterations = 5)
|
||||||
|
@Measurement(iterations = 10)
|
||||||
|
@Threads(8)
|
||||||
|
public class ByteBufAllocatorConcurrentBenchmark extends AbstractMicrobenchmark {
|
||||||
|
|
||||||
|
private static final ByteBufAllocator unpooledAllocator = new UnpooledByteBufAllocator(true, true);
|
||||||
|
|
||||||
|
@Param({ "00064", "00256", "01024", "04096" })
|
||||||
|
public int size;
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
public boolean allocateRelease() {
|
||||||
|
return unpooledAllocator.directBuffer(size).release();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user