diff --git a/build.xml b/build.xml
index b97049307dc9..5c06005ca814 100644
--- a/build.xml
+++ b/build.xml
@@ -154,7 +154,7 @@
-
+
diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
index d8c0dbc97b8b..5480636ebfd5 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
@@ -221,7 +221,7 @@ public long unsharedHeapSize()
public long unsharedHeapSizeExcludingData()
{
return EMPTY_SIZE
- + ObjectSizes.sizeOnHeapExcludingData(bytes)
+ + ObjectSizes.sizeOnHeapExcludingDataOf(bytes)
+ ObjectSizes.sizeOf(text);
}
diff --git a/src/java/org/apache/cassandra/db/BufferClustering.java b/src/java/org/apache/cassandra/db/BufferClustering.java
index 0423c26ccdf3..625b9387449f 100644
--- a/src/java/org/apache/cassandra/db/BufferClustering.java
+++ b/src/java/org/apache/cassandra/db/BufferClustering.java
@@ -53,7 +53,7 @@ public long unsharedHeapSizeExcludingData()
{
if (this == Clustering.EMPTY || this == Clustering.STATIC_CLUSTERING)
return 0;
- return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(values);
+ return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingDataOf(values);
}
public static BufferClustering make(ByteBuffer... values)
diff --git a/src/java/org/apache/cassandra/db/rows/BufferCell.java b/src/java/org/apache/cassandra/db/rows/BufferCell.java
index fc85b3973aa0..1280a3fded25 100644
--- a/src/java/org/apache/cassandra/db/rows/BufferCell.java
+++ b/src/java/org/apache/cassandra/db/rows/BufferCell.java
@@ -145,6 +145,6 @@ public Cell> clone(ByteBufferCloner cloner)
public long unsharedHeapSizeExcludingData()
{
- return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(value) + (path == null ? 0 : path.unsharedHeapSizeExcludingData());
+ return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingDataOf(value) + (path == null ? 0 : path.unsharedHeapSizeExcludingData());
}
}
diff --git a/src/java/org/apache/cassandra/db/rows/CellPath.java b/src/java/org/apache/cassandra/db/rows/CellPath.java
index aacccf30ba13..9354754546bc 100644
--- a/src/java/org/apache/cassandra/db/rows/CellPath.java
+++ b/src/java/org/apache/cassandra/db/rows/CellPath.java
@@ -128,7 +128,7 @@ public CellPath clone(ByteBufferCloner cloner)
public long unsharedHeapSizeExcludingData()
{
- return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(value);
+ return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingDataOf(value);
}
}
diff --git a/src/java/org/apache/cassandra/db/tries/MemtableTrie.java b/src/java/org/apache/cassandra/db/tries/MemtableTrie.java
index cee72e9fc828..a829f23f3430 100644
--- a/src/java/org/apache/cassandra/db/tries/MemtableTrie.java
+++ b/src/java/org/apache/cassandra/db/tries/MemtableTrie.java
@@ -33,6 +33,8 @@
import org.apache.cassandra.utils.ObjectSizes;
import org.github.jamm.MemoryLayoutSpecification;
+import static org.github.jamm.MemoryMeterStrategy.MEMORY_LAYOUT;
+
/**
* Memtable trie, i.e. an in-memory trie built for fast modification and reads executing concurrently with writes from
* a single mutator thread.
@@ -982,7 +984,7 @@ public long sizeOffHeap()
/** Returns the on heap size of the memtable trie itself, not counting any space taken by referenced content. */
public long sizeOnHeap()
{
- return contentCount * MemoryLayoutSpecification.SPEC.getReferenceSize() +
+ return contentCount * (long) MEMORY_LAYOUT.getReferenceSize() +
(bufferType == BufferType.ON_HEAP ? allocatedPos + EMPTY_SIZE_ON_HEAP : EMPTY_SIZE_OFF_HEAP);
}
diff --git a/src/java/org/apache/cassandra/fql/FullQueryLogger.java b/src/java/org/apache/cassandra/fql/FullQueryLogger.java
index 8a145c66e9ca..7279a586d99e 100644
--- a/src/java/org/apache/cassandra/fql/FullQueryLogger.java
+++ b/src/java/org/apache/cassandra/fql/FullQueryLogger.java
@@ -52,6 +52,7 @@
import org.github.jamm.MemoryLayoutSpecification;
import static com.google.common.base.Preconditions.checkNotNull;
+import static org.github.jamm.MemoryMeterStrategy.MEMORY_LAYOUT;
/**
* A logger that logs entire query contents after the query finishes (or times out).
@@ -84,8 +85,8 @@ public class FullQueryLogger implements QueryEvents.Listener
private static final int EMPTY_LIST_SIZE = Ints.checkedCast(ObjectSizes.measureDeep(new ArrayList<>(0)));
private static final int EMPTY_BYTEBUF_SIZE;
- private static final int OBJECT_HEADER_SIZE = MemoryLayoutSpecification.SPEC.getObjectHeaderSize();
- private static final int OBJECT_REFERENCE_SIZE = MemoryLayoutSpecification.SPEC.getReferenceSize();
+ private static final int OBJECT_HEADER_SIZE = MEMORY_LAYOUT.getObjectHeaderSize();
+ private static final int OBJECT_REFERENCE_SIZE = MEMORY_LAYOUT.getReferenceSize();
public static final FullQueryLogger instance = new FullQueryLogger();
diff --git a/src/java/org/apache/cassandra/index/sai/disk/v1/kdtree/BKDPostingsIndex.java b/src/java/org/apache/cassandra/index/sai/disk/v1/kdtree/BKDPostingsIndex.java
index 6fcc44051b70..36c3e98c4164 100644
--- a/src/java/org/apache/cassandra/index/sai/disk/v1/kdtree/BKDPostingsIndex.java
+++ b/src/java/org/apache/cassandra/index/sai/disk/v1/kdtree/BKDPostingsIndex.java
@@ -57,13 +57,6 @@ class BKDPostingsIndex
}
}
- public long memoryUsage()
- {
- // IntLongHashMap uses two arrays: one for keys, one for values.
- return MemoryLayoutSpecification.sizeOfArray(index.size(), 4L)
- + MemoryLayoutSpecification.sizeOfArray(index.size(), 8L);
- }
-
/**
* Returns true if given node ID has an auxiliary posting list.
*/
diff --git a/src/java/org/apache/cassandra/utils/ObjectSizes.java b/src/java/org/apache/cassandra/utils/ObjectSizes.java
index 468522c6ff06..bd45ea34ddf0 100644
--- a/src/java/org/apache/cassandra/utils/ObjectSizes.java
+++ b/src/java/org/apache/cassandra/utils/ObjectSizes.java
@@ -19,25 +19,33 @@
package org.apache.cassandra.utils;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
import java.nio.ByteBuffer;
-import org.github.jamm.MemoryLayoutSpecification;
import org.github.jamm.MemoryMeter;
+import org.github.jamm.MemoryMeter.ByteBufferMode;
+import org.github.jamm.MemoryMeter.Guess;
+
+import static org.github.jamm.MemoryMeterStrategy.MEMORY_LAYOUT;
+import static org.github.jamm.utils.ArrayMeasurementUtils.computeArraySize;
/**
- * A convenience class for wrapping access to MemoryMeter
+ * A convenience class for wrapping access to MemoryMeter. Should be used instead of using a {@code MemoryMeter} directly.
+ * {@code MemoryMeter} can be used directly for testing as it allow a more fine tuned configuration for comparison.
*/
public class ObjectSizes
{
- private static final MemoryMeter meter = new MemoryMeter().omitSharedBufferOverhead()
- .withGuessing(MemoryMeter.Guess.FALLBACK_UNSAFE)
- .ignoreKnownSingletons();
+ private static final MemoryMeter meter = MemoryMeter.builder().withGuessing(Guess.INSTRUMENTATION_AND_SPECIFICATION,
+ Guess.UNSAFE)
+ .build();
- private static final long EMPTY_HEAP_BUFFER_SIZE = measure(ByteBufferUtil.EMPTY_BYTE_BUFFER);
- private static final long EMPTY_BYTE_ARRAY_SIZE = measure(new byte[0]);
- private static final long EMPTY_STRING_SIZE = measure("");
+ private static final long HEAP_BUFFER_SHALLOW_SIZE = measure(ByteBufferUtil.EMPTY_BYTE_BUFFER);
+ private static final long DIRECT_BUFFER_SHALLOW_SIZE = measure(ByteBuffer.allocateDirect(0));
+ private static final long DIRECT_BUFFER_DEEP_SIZE = measureDeep(ByteBuffer.allocateDirect(0));
- private static final long DIRECT_BUFFER_HEAP_SIZE = measure(ByteBuffer.allocateDirect(0));
+ public static final long IPV6_SOCKET_ADDRESS_SIZE = ObjectSizes.measureDeep(new InetSocketAddress(getIpvAddress(16), 42));
/**
* Memory a byte array consumes
@@ -47,10 +55,7 @@ public class ObjectSizes
*/
public static long sizeOfArray(byte[] bytes)
{
- if (bytes == null)
- return 0;
-
- return sizeOfArray(bytes.length, 1);
+ return meter.measureArray(bytes);
}
/**
@@ -61,10 +66,7 @@ public static long sizeOfArray(byte[] bytes)
*/
public static long sizeOfArray(long[] longs)
{
- if (longs == null)
- return 0;
-
- return sizeOfArray(longs.length, 8);
+ return meter.measureArray(longs);
}
/**
@@ -75,10 +77,7 @@ public static long sizeOfArray(long[] longs)
*/
public static long sizeOfArray(int[] ints)
{
- if (ints == null)
- return 0;
-
- return sizeOfArray(ints.length, 4);
+ return meter.measureArray(ints);
}
/**
@@ -89,7 +88,7 @@ public static long sizeOfArray(int[] ints)
*/
public static long sizeOfReferenceArray(int length)
{
- return sizeOfArray(length, MemoryLayoutSpecification.SPEC.getReferenceSize());
+ return sizeOfArray(length, MEMORY_LAYOUT.getReferenceSize());
}
/**
@@ -100,15 +99,12 @@ public static long sizeOfReferenceArray(int length)
*/
public static long sizeOfArray(Object[] objects)
{
- if (objects == null)
- return 0;
-
- return sizeOfReferenceArray(objects.length);
+ return meter.measureArray(objects);
}
- private static long sizeOfArray(int length, long elementSize)
+ private static long sizeOfArray(int length, int elementSize)
{
- return MemoryLayoutSpecification.sizeOfArray(length, elementSize);
+ return computeArraySize(MEMORY_LAYOUT.getArrayHeaderSize(), length, elementSize, MEMORY_LAYOUT.getObjectAlignment());
}
/**
@@ -129,65 +125,89 @@ public static long sizeOnHeapOf(ByteBuffer[] array)
/**
* Amount of non-data heap memory consumed by the array of byte buffers. It sums memory consumed
- * by the array itself and for each included byte buffer using {@link #sizeOnHeapExcludingData(ByteBuffer)}.
+ * by the array itself and for each included byte buffer using {@link #sizeOnHeapExcludingDataOf(ByteBuffer)}.
*/
- public static long sizeOnHeapExcludingData(ByteBuffer[] array)
+ public static long sizeOnHeapExcludingDataOf(ByteBuffer[] array)
{
if (array == null)
return 0;
long sum = sizeOfArray(array);
for (ByteBuffer b : array)
- sum += sizeOnHeapExcludingData(b);
+ sum += sizeOnHeapExcludingDataOf(b);
return sum;
}
/**
- * @return heap memory consumed by the byte buffer. If it is a slice, it counts the data size, but it does not
- * include the internal array overhead.
+ * Measures the heap memory used by the specified byte buffer. If the buffer is a slab only the data size will be
+ * counted but not the internal overhead. A SLAB is assumed to be created by: {@code buffer.duplicate().position(start).limit(end)} without the use of {@code slice()}.
+ *
This method makes a certain amount of assumptions:
+ *
+ * - That slabs are always created using: {@code buffer.duplicate().position(start).limit(end)} and not through slice
+ * - That the input buffers are not read-only buffers
+ * - That the direct buffers that are not slab are not duplicates
+ *
+ * Non-respect of those assumptions can lead to an invalid value being returned.
+ * @param buffer the buffer to measure
+ * @return the heap memory used by the specified byte buffer.
*/
public static long sizeOnHeapOf(ByteBuffer buffer)
{
if (buffer == null)
return 0;
- if (buffer.isDirect())
- return DIRECT_BUFFER_HEAP_SIZE;
+ assert !buffer.isReadOnly();
- int arrayLen = buffer.array().length;
- int bufLen = buffer.remaining();
+ // We assume here that slabs are always created using: buffer.duplicate().position(start).limit(end) and not through slice
+ if (ByteBufferMode.SLAB_ALLOCATION_NO_SLICE.isSlab(buffer))
+ {
+ if (buffer.isDirect())
+ return DIRECT_BUFFER_SHALLOW_SIZE; // We ignore the underlying buffer
- // if we're only referencing a sub-portion of the ByteBuffer, don't count the array overhead (assume it is SLAB
- // allocated - the overhead amortized over all the allocations is negligible and better to undercount than over)
- if (arrayLen > bufLen)
- return EMPTY_HEAP_BUFFER_SIZE + bufLen;
+ return HEAP_BUFFER_SHALLOW_SIZE + buffer.remaining(); // We ignore the array overhead
+ }
- return EMPTY_HEAP_BUFFER_SIZE + (arrayLen == 0 ? EMPTY_BYTE_ARRAY_SIZE : sizeOfArray(arrayLen, 1));
+ if (buffer.isDirect())
+ return DIRECT_BUFFER_DEEP_SIZE; // That might not be true if the buffer is a view of another buffer so we could undercount
+
+ return HEAP_BUFFER_SHALLOW_SIZE + meter.measureArray(buffer.array());
}
/**
- * @return non-data heap memory consumed by the byte buffer. If it is a slice, it does not include the internal
- * array overhead.
+ * Measures the heap memory used by the specified byte buffer excluding the data. If the buffer shallow size will be counted.
+ * A SLAB is assumed to be created by: {@code buffer.duplicate().position(start).limit(end)} without the use of {@code slice()}.
+ * This method makes a certain amount of assumptions:
+ *
+ * - That slabs are always created using: {@code buffer.duplicate().position(start).limit(end)} and not through slice
+ * - That the input buffers are not read-only buffers
+ * - That the direct buffers that are not slab are not duplicates
+ *
+ * Non-respect of those assumptions can lead to an invalid value being returned. T
+ * @param buffer the buffer to measure
+ * @return the heap memory used by the specified byte buffer excluding the data..
*/
- public static long sizeOnHeapExcludingData(ByteBuffer buffer)
+ public static long sizeOnHeapExcludingDataOf(ByteBuffer buffer)
{
if (buffer == null)
return 0;
+ assert !buffer.isReadOnly();
+
+ // We assume here that slabs are always created using: buffer.duplicate().position(start).limit(end) and not through slice
+ if (ByteBufferMode.SLAB_ALLOCATION_NO_SLICE.isSlab(buffer))
+ {
if (buffer.isDirect())
- return DIRECT_BUFFER_HEAP_SIZE;
+ return DIRECT_BUFFER_SHALLOW_SIZE; // We ignore the underlying buffer
- int arrayLen = buffer.array().length;
- int bufLen = buffer.remaining();
+ return HEAP_BUFFER_SHALLOW_SIZE; // We ignore the array overhead
+ }
- // if we're only referencing a sub-portion of the ByteBuffer, don't count the array overhead (assume it is SLAB
- // allocated - the overhead amortized over all the allocations is negligible and better to undercount than over)
- if (arrayLen > bufLen)
- return EMPTY_HEAP_BUFFER_SIZE;
+ if (buffer.isDirect())
+ return DIRECT_BUFFER_DEEP_SIZE; // That might not be true if the buffer is a view of another buffer so we could undercount
- // If buffers are dedicated, account for byte array size and any padding overhead
- return EMPTY_HEAP_BUFFER_SIZE + (arrayLen == 0 ? EMPTY_BYTE_ARRAY_SIZE : (sizeOfArray(arrayLen, 1) - arrayLen));
+ byte[] bytes = buffer.array();
+ return HEAP_BUFFER_SHALLOW_SIZE + meter.measureArray(bytes) - bytes.length;
}
/**
@@ -196,13 +216,9 @@ public static long sizeOnHeapExcludingData(ByteBuffer buffer)
* @param str String to calculate memory size of
* @return Total in-memory size of the String
*/
- // TODO hard coding this to 2 isn't necessarily correct in Java 11
public static long sizeOf(String str)
{
- if (str == null)
- return 0;
-
- return EMPTY_STRING_SIZE + sizeOfArray(str.length(), Character.BYTES);
+ return meter.measureStringDeep(str);
}
/**
@@ -216,6 +232,18 @@ public static long measureDeep(Object pojo)
return meter.measureDeep(pojo);
}
+ /**
+ * @param pojo the object to measure
+ * @return The size on the heap of the instance and all retained heap referenced by it, excluding portions of
+ * ByteBuffer that are not directly referenced by it but including any other referenced that may also be retained
+ * by other objects. This also includes bytes referenced in direct byte buffers, and may double-count memory if
+ * it is referenced by multiple ByteBuffer copies.
+ */
+ public static long measureDeepOmitShared(Object pojo)
+ {
+ return meter.measureDeep(pojo, ByteBufferMode.SLAB_ALLOCATION_NO_SLICE);
+ }
+
/**
* @param pojo the object to measure
* @return the size on the heap of the instance only, excluding any referenced objects
@@ -224,4 +252,20 @@ public static long measure(Object pojo)
{
return meter.measure(pojo);
}
+
+ private static InetAddress getIpvAddress(int size)
+ {
+ if (size == 16 || size ==4)
+ {
+ try
+ {
+ return InetAddress.getByAddress(new byte[size]);
+ }
+ catch (UnknownHostException e)
+ {
+ throw new IllegalArgumentException("Invalid size of a byte array when getting and ipv address: " + size);
+ }
+ }
+ else throw new IllegalArgumentException("Excpected a byte array size of 4 or 16 for an ipv address but got: " + size);
+ }
}
diff --git a/test/unit/org/apache/cassandra/db/CellSpecTest.java b/test/unit/org/apache/cassandra/db/CellSpecTest.java
index df6d7dcba0fc..0b0bdf46741a 100644
--- a/test/unit/org/apache/cassandra/db/CellSpecTest.java
+++ b/test/unit/org/apache/cassandra/db/CellSpecTest.java
@@ -84,7 +84,7 @@ public void unsharedHeapSizeExcludingData()
private static long valuePtrSize(Object value)
{
if (value instanceof ByteBuffer)
- return ObjectSizes.sizeOnHeapExcludingData((ByteBuffer) value);
+ return ObjectSizes.sizeOnHeapExcludingDataOf((ByteBuffer) value);
else if (value instanceof byte[])
return ObjectSizes.sizeOfArray((byte[]) value) - ((byte[]) value).length;
throw new IllegalArgumentException("Unsupported type by valuePtrSize: " + value.getClass());
diff --git a/test/unit/org/apache/cassandra/db/memtable/MemtableSizeTestBase.java b/test/unit/org/apache/cassandra/db/memtable/MemtableSizeTestBase.java
index e6df26f31deb..43998f0eb15b 100644
--- a/test/unit/org/apache/cassandra/db/memtable/MemtableSizeTestBase.java
+++ b/test/unit/org/apache/cassandra/db/memtable/MemtableSizeTestBase.java
@@ -47,8 +47,9 @@ public abstract class MemtableSizeTestBase extends CQLTester
// The meter in ObjectSizes uses omitSharedBufferOverhead which counts off-heap data too
// Note: To see a printout of the usage for each object, add .enableDebug() here (most useful with smaller number of
// partitions).
- static final MemoryMeter meter = new MemoryMeter().ignoreKnownSingletons()
- .withGuessing(MemoryMeter.Guess.FALLBACK_UNSAFE);
+ private static final MemoryMeter meter = MemoryMeter.builder()
+ .withGuessing(MemoryMeter.Guess.INSTRUMENTATION, MemoryMeter.Guess.UNSAFE)
+ .build();
static String keyspace;
String table;
diff --git a/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java b/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java
index a4c77bccc411..28d93eeb16c5 100644
--- a/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java
+++ b/test/unit/org/apache/cassandra/utils/ObjectSizesTest.java
@@ -22,128 +22,123 @@
import org.junit.Test;
-import org.github.jamm.MemoryLayoutSpecification;
import org.github.jamm.MemoryMeter;
+import org.github.jamm.MemoryMeter.Guess;
-import static org.assertj.core.api.Assertions.assertThat;
+import static org.github.jamm.MemoryMeter.ByteBufferMode.SLAB_ALLOCATION_NO_SLICE;
+import static org.junit.Assert.assertEquals;
public class ObjectSizesTest
{
- private static final MemoryMeter meter = new MemoryMeter().withGuessing(MemoryMeter.Guess.FALLBACK_UNSAFE).omitSharedBufferOverhead().ignoreKnownSingletons();
-
- private static final long EMPTY_HEAP_BUFFER_RAW_SIZE = meter.measure(ByteBuffer.allocate(0));
- private static final long EMPTY_OFFHEAP_BUFFER_RAW_SIZE = meter.measure(ByteBuffer.allocateDirect(0));
- private static final ByteBuffer[] EMPTY_BYTE_BUFFER_ARRAY = new ByteBuffer[0];
-
- public static final long REF_ARRAY_0_SIZE = MemoryLayoutSpecification.sizeOfArray(0, MemoryLayoutSpecification.SPEC.getReferenceSize());
- public static final long REF_ARRAY_1_SIZE = MemoryLayoutSpecification.sizeOfArray(1, MemoryLayoutSpecification.SPEC.getReferenceSize());
- public static final long REF_ARRAY_2_SIZE = MemoryLayoutSpecification.sizeOfArray(2, MemoryLayoutSpecification.SPEC.getReferenceSize());
-
- public static final long BYTE_ARRAY_0_SIZE = MemoryLayoutSpecification.sizeOfArray(0, 1);
- public static final long BYTE_ARRAY_10_SIZE = MemoryLayoutSpecification.sizeOfArray(10, 1);
- public static final long BYTE_ARRAY_10_EXCEPT_DATA_SIZE = MemoryLayoutSpecification.sizeOfArray(10, 1) - 10;
-
- private ByteBuffer buf10 = ByteBuffer.allocate(10);
- private ByteBuffer prefixBuf8 = buf10.duplicate();
- private ByteBuffer suffixBuf9 = buf10.duplicate();
- private ByteBuffer infixBuf7 = buf10.duplicate();
-
- {
- prefixBuf8.limit(8);
-
- suffixBuf9.position(1);
- suffixBuf9 = suffixBuf9.slice();
-
- infixBuf7.limit(8);
- infixBuf7.position(1);
- infixBuf7 = infixBuf7.slice();
- }
+ // We use INSTRUMENTATION as principal strategy as it is our reference strategy
+ private static final MemoryMeter meter = MemoryMeter.builder()
+ .withGuessing(Guess.INSTRUMENTATION, Guess.UNSAFE)
+ .build();
@Test
public void testSizeOnHeapExcludingData()
{
- // empty array of byte buffers
- ByteBuffer[] buffers = EMPTY_BYTE_BUFFER_ARRAY;
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_0_SIZE);
-
// single empty heap buffer
- buffers = new ByteBuffer[]{ ByteBuffer.allocate(0) };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE);
+ checkBufferSizeExcludingData(ByteBuffer.allocate(0), 0);
// single non-empty heap buffer
- buffers = new ByteBuffer[]{ buf10 };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_EXCEPT_DATA_SIZE);
+ checkBufferSizeExcludingData(ByteBuffer.allocate(10), 10);
// single empty direct buffer
- buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(0) };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ checkBufferSizeExcludingData(ByteBuffer.allocateDirect(0), 0);
// single non-empty direct buffer
- buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(10) };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ checkBufferSizeExcludingData(ByteBuffer.allocateDirect(10), 0);
+
+ // heap buffer being a prefix slab
+ ByteBuffer buffer = (ByteBuffer) ByteBuffer.allocate(10).duplicate().limit(8);
+ checkBufferSizeExcludingData(buffer, 8);
- // two different empty byte buffers
- buffers = new ByteBuffer[]{ ByteBuffer.allocate(0), ByteBuffer.allocateDirect(0) };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_2_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ // heap buffer being a suffix slab
+ buffer = (ByteBuffer) ByteBuffer.allocate(10).duplicate().position(1);
+ checkBufferSizeExcludingData(buffer, 9);
+
+ // heap buffer being an infix slab
+ buffer = (ByteBuffer) ByteBuffer.allocate(10).duplicate().position(1).limit(8);
+ checkBufferSizeExcludingData(buffer, 7);
+ }
- // two different non-empty byte buffers
- buffers = new ByteBuffer[]{ buf10, ByteBuffer.allocateDirect(500) };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_2_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_EXCEPT_DATA_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ private void checkBufferSizeExcludingData(ByteBuffer buffer, int dataSize)
+ {
+ assertEquals(meter.measureDeep(buffer, SLAB_ALLOCATION_NO_SLICE) - dataSize, ObjectSizes.sizeOnHeapExcludingDataOf(buffer));
+ }
- // heap buffer being a prefix slice of other buffer
- buffers = new ByteBuffer[]{ prefixBuf8 };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE);
+ @Test
+ public void testSizeOnHeapExcludingDataArray()
+ {
+ checkBufferSizeExcludingDataArray(0, new ByteBuffer[0]);
- // heap buffer being a suffix slice of other buffer
- buffers = new ByteBuffer[]{ suffixBuf9 };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE);
+ // single heap buffer
+ checkBufferSizeExcludingDataArray(0, ByteBuffer.allocate(0));
- // heap buffer being an infix slice of other buffer
- buffers = new ByteBuffer[]{ infixBuf7 };
- assertThat(ObjectSizes.sizeOnHeapExcludingData(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE);
+ // multiple buffers
+ checkBufferSizeExcludingDataArray(10, ByteBuffer.allocate(0), ByteBuffer.allocate(10), ByteBuffer.allocateDirect(10));
+
+ // heap buffer being a prefix slab
+ ByteBuffer prefix = (ByteBuffer) ByteBuffer.allocate(10).duplicate().limit(8);
+
+ // heap buffer being a suffix slab
+ ByteBuffer suffix = (ByteBuffer) ByteBuffer.allocate(10).duplicate().position(1);
+ checkBufferSizeExcludingDataArray(8 + 9, prefix, suffix);
+ }
+
+ private void checkBufferSizeExcludingDataArray(int dataSize, ByteBuffer... buffers)
+ {
+ assertEquals(meter.measureDeep(buffers, SLAB_ALLOCATION_NO_SLICE) - dataSize, ObjectSizes.sizeOnHeapExcludingDataOf(buffers));
}
@Test
public void testSizeOnHeapOf()
{
- // empty array of byte buffers
- ByteBuffer[] buffers = EMPTY_BYTE_BUFFER_ARRAY;
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_0_SIZE);
-
// single empty heap buffer
- buffers = new ByteBuffer[]{ ByteBuffer.allocate(0) };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE);
+ checkBufferSize(ByteBuffer.allocate(0));
// single non-empty heap buffer
- buffers = new ByteBuffer[]{ buf10 };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_SIZE);
+ checkBufferSize(ByteBuffer.allocate(10));
// single empty direct buffer
- buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(0) };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ checkBufferSize(ByteBuffer.allocateDirect(0));
// single non-empty direct buffer
- buffers = new ByteBuffer[]{ ByteBuffer.allocateDirect(10) };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ checkBufferSize(ByteBuffer.allocateDirect(10));
+
+ // heap buffer being a prefix slab
+ ByteBuffer buffer = (ByteBuffer) ByteBuffer.allocate(10).duplicate().limit(8);
+ checkBufferSize(buffer);
+
+ // heap buffer being a suffix slab
+ buffer = (ByteBuffer) ByteBuffer.allocate(10).duplicate().position(1);
+ checkBufferSize(buffer);
- // two different empty byte buffers
- buffers = new ByteBuffer[]{ ByteBuffer.allocate(0), ByteBuffer.allocateDirect(0) };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_2_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_0_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ // heap buffer being an infix slab
+ buffer = (ByteBuffer) ByteBuffer.allocate(10).duplicate().position(1).limit(8);
+ checkBufferSize(buffer);
+ }
+
+ private void checkBufferSize(ByteBuffer buffer)
+ {
+ assertEquals(meter.measureDeep(buffer, SLAB_ALLOCATION_NO_SLICE), ObjectSizes.sizeOnHeapOf(buffer));
+ }
- // two different non-empty byte buffers
- buffers = new ByteBuffer[]{ buf10, ByteBuffer.allocateDirect(500) };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_2_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + BYTE_ARRAY_10_SIZE + EMPTY_OFFHEAP_BUFFER_RAW_SIZE);
+ @Test
+ public void testSizeOnHeapOfArray()
+ {
+ checkBufferArraySize(new ByteBuffer[0]);
- // heap buffer being a prefix slice of other buffer
- buffers = new ByteBuffer[]{ prefixBuf8 };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + 8);
+ // single heap buffer
+ checkBufferArraySize(ByteBuffer.allocate(0));
- // heap buffer being a suffix slice of other buffer
- buffers = new ByteBuffer[]{ suffixBuf9 };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + 9);
+ // multiple buffers
+ checkBufferArraySize(ByteBuffer.allocate(0), ByteBuffer.allocate(10), ByteBuffer.allocateDirect(10));
+ }
- // heap buffer being an infix slice of other buffer
- buffers = new ByteBuffer[]{ infixBuf7 };
- assertThat(ObjectSizes.sizeOnHeapOf(buffers)).isEqualTo(REF_ARRAY_1_SIZE + EMPTY_HEAP_BUFFER_RAW_SIZE + 7);
+ private void checkBufferArraySize(ByteBuffer... buffers)
+ {
+ assertEquals(meter.measureDeep(buffers, SLAB_ALLOCATION_NO_SLICE), ObjectSizes.sizeOnHeapOf(buffers));
}
}
\ No newline at end of file