diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java index cf6bafa8320..ee5c40a3f4f 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransaction.java @@ -14,6 +14,24 @@ */ package org.hyperledger.besu.ethereum.eth.transactions; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_ENTRY_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_STORAGE_KEY_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOBS_WITH_COMMITMENTS_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOB_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.CODE_DELEGATION_ENTRY_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.EIP1559_AND_EIP4844_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.KZG_COMMITMENT_OR_PROOF_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_ACCESS_LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CHAIN_ID_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_TO_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PAYLOAD_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PENDING_TRANSACTION_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.VERSIONED_HASH_SIZE; + import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Hash; @@ -31,23 +49,6 @@ public abstract class PendingTransaction implements org.hyperledger.besu.datatypes.PendingTransaction { static final int NOT_INITIALIZED = -1; - static final int FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE = 904; - static final int EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE = 1016; - static final int OPTIONAL_TO_MEMORY_SIZE = 112; - static final int OPTIONAL_CHAIN_ID_MEMORY_SIZE = 80; - static final int PAYLOAD_BASE_MEMORY_SIZE = 32; - static final int ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE = 32; - static final int ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE = 248; - static final int OPTIONAL_ACCESS_LIST_MEMORY_SIZE = 40; - static final int OPTIONAL_CODE_DELEGATION_LIST_MEMORY_SIZE = 40; - static final int CODE_DELEGATION_ENTRY_MEMORY_SIZE = 432; - static final int VERSIONED_HASH_SIZE = 96; - static final int BASE_LIST_SIZE = 48; - static final int BASE_OPTIONAL_SIZE = 16; - static final int KZG_COMMITMENT_OR_PROOF_SIZE = 112; - static final int BLOB_SIZE = 131136; - static final int BLOBS_WITH_COMMITMENTS_SIZE = 40; - static final int PENDING_TRANSACTION_MEMORY_SIZE = 40; private static final AtomicLong TRANSACTIONS_ADDED = new AtomicLong(); private final Transaction transaction; private final long addedAt; @@ -151,18 +152,18 @@ private int computeMemorySize() { case BLOB -> computeBlobMemorySize(); case DELEGATE_CODE -> computeDelegateCodeMemorySize(); } - + PENDING_TRANSACTION_MEMORY_SIZE; + + PENDING_TRANSACTION_SHALLOW_SIZE; } private int computeFrontierMemorySize() { - return FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE + return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE + computePayloadMemorySize() + computeToMemorySize() + computeChainIdMemorySize(); } private int computeAccessListMemorySize() { - return FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE + return FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE + computePayloadMemorySize() + computeToMemorySize() + computeChainIdMemorySize() @@ -170,7 +171,7 @@ private int computeAccessListMemorySize() { } private int computeEIP1559MemorySize() { - return EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE + return EIP1559_AND_EIP4844_SHALLOW_SIZE + computePayloadMemorySize() + computeToMemorySize() + computeChainIdMemorySize() @@ -179,7 +180,7 @@ private int computeEIP1559MemorySize() { private int computeBlobMemorySize() { return computeEIP1559MemorySize() - + BASE_OPTIONAL_SIZE // for the versionedHashes field + + OPTIONAL_SHALLOW_SIZE // for the versionedHashes field + computeBlobWithCommitmentsMemorySize(); } @@ -190,9 +191,9 @@ private int computeDelegateCodeMemorySize() { private int computeBlobWithCommitmentsMemorySize() { final int blobCount = transaction.getBlobCount(); - return BASE_OPTIONAL_SIZE + return OPTIONAL_SHALLOW_SIZE + BLOBS_WITH_COMMITMENTS_SIZE - + (BASE_LIST_SIZE * 4) + + (LIST_SHALLOW_SIZE * 4) + (KZG_COMMITMENT_OR_PROOF_SIZE * blobCount * 2) + (VERSIONED_HASH_SIZE * blobCount) + (BLOB_SIZE * blobCount); @@ -200,20 +201,20 @@ private int computeBlobWithCommitmentsMemorySize() { private int computePayloadMemorySize() { return !transaction.getPayload().isEmpty() - ? PAYLOAD_BASE_MEMORY_SIZE + transaction.getPayload().size() + ? PAYLOAD_SHALLOW_SIZE + transaction.getPayload().size() : 0; } private int computeToMemorySize() { if (transaction.getTo().isPresent()) { - return OPTIONAL_TO_MEMORY_SIZE; + return OPTIONAL_TO_SIZE; } return 0; } private int computeChainIdMemorySize() { if (transaction.getChainId().isPresent()) { - return OPTIONAL_CHAIN_ID_MEMORY_SIZE; + return OPTIONAL_CHAIN_ID_SIZE; } return 0; } @@ -223,11 +224,11 @@ private int computeAccessListEntriesMemorySize() { .getAccessList() .map( al -> { - int totalSize = OPTIONAL_ACCESS_LIST_MEMORY_SIZE; - totalSize += al.size() * ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE; + int totalSize = OPTIONAL_ACCESS_LIST_SHALLOW_SIZE; + totalSize += al.size() * ACCESS_LIST_ENTRY_SHALLOW_SIZE; totalSize += al.stream().map(AccessListEntry::storageKeys).mapToInt(List::size).sum() - * ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE; + * ACCESS_LIST_STORAGE_KEY_SIZE; return totalSize; }) .orElse(0); @@ -238,8 +239,8 @@ private int computeCodeDelegationListMemorySize() { .getCodeDelegationList() .map( cd -> { - int totalSize = OPTIONAL_CODE_DELEGATION_LIST_MEMORY_SIZE; - totalSize += cd.size() * CODE_DELEGATION_ENTRY_MEMORY_SIZE; + int totalSize = OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE; + totalSize += cd.size() * CODE_DELEGATION_ENTRY_SIZE; return totalSize; }) .orElse(0); @@ -413,4 +414,29 @@ public boolean hasPriority() { } } } + + /** + * The memory size of an object is calculated using the PendingTransactionEstimatedMemorySizeTest + * look there for the details of the calculation and to adapt the code when any of the related + * class changes its structure. + */ + public interface MemorySize { + int FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE = 904; + int EIP1559_AND_EIP4844_SHALLOW_SIZE = 1016; + int OPTIONAL_TO_SIZE = 112; + int OPTIONAL_CHAIN_ID_SIZE = 80; + int PAYLOAD_SHALLOW_SIZE = 32; + int ACCESS_LIST_STORAGE_KEY_SIZE = 32; + int ACCESS_LIST_ENTRY_SHALLOW_SIZE = 248; + int OPTIONAL_ACCESS_LIST_SHALLOW_SIZE = 40; + int OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE = 40; + int CODE_DELEGATION_ENTRY_SIZE = 432; + int VERSIONED_HASH_SIZE = 96; + int LIST_SHALLOW_SIZE = 48; + int OPTIONAL_SHALLOW_SIZE = 16; + int KZG_COMMITMENT_OR_PROOF_SIZE = 112; + int BLOB_SIZE = 131136; + int BLOBS_WITH_COMMITMENTS_SIZE = 40; + int PENDING_TRANSACTION_SHALLOW_SIZE = 40; + } } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java index c80f5ca1ad4..7c2722937e3 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java @@ -15,6 +15,22 @@ package org.hyperledger.besu.ethereum.eth.transactions; import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_ENTRY_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.ACCESS_LIST_STORAGE_KEY_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOBS_WITH_COMMITMENTS_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.BLOB_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.CODE_DELEGATION_ENTRY_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.EIP1559_AND_EIP4844_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.KZG_COMMITMENT_OR_PROOF_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_ACCESS_LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CHAIN_ID_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.OPTIONAL_TO_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PAYLOAD_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.PENDING_TRANSACTION_SHALLOW_SIZE; +import static org.hyperledger.besu.ethereum.eth.transactions.PendingTransaction.MemorySize.VERSIONED_HASH_SIZE; import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.datatypes.AccessListEntry; @@ -58,16 +74,53 @@ import org.openjdk.jol.info.GraphVisitor; import org.openjdk.jol.info.GraphWalker; -@EnabledOnOs(OS.LINUX) +/** + * This test class has a double utility, first it is used to verify that the current memory size of + * a pending transaction object correspond to the calculated values, so if any of the tests in this + * file fails, it probably means that one of the related classes has changed its format, and a new + * calculation needs to be done. + * + *

The second utility is to help with the calculation of the memory size of a class, using the JOL Tool, to navigate the class layout and collect the + * reported memory sizes. + * + *

For a correct calculation there are some things to consider, first exclude from the + * calculation any reference to a constant object, for example if a field is always a + * reference to {@code Optional.empty()} then just count the reference size, but not the size of the + * Optional since it is always the same instance for every pending transaction. + * + *

To study the layout of a class it is usually useful to create a test method with one or more + * instance of it, then programmatically save a heap dump using the {@link #dumpHeap(String, + * boolean)} method, then analyze the heap dump with a tool to identify which are the dynamic and + * constant fields, then use the JOL Tool to print the class layout and walk in the object tree, + * then complete the writing of the test that will verify the current amount of memory used by that + * class. + */ +@EnabledOnOs({OS.LINUX, OS.MAC}) public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPoolTest { + /** + * Classes that represent constant instances, across all pending transaction types, and are ignored during the calculation + */ private static final Set> SHARED_CLASSES = Set.of(SignatureAlgorithm.class, TransactionType.class); + /** + * Field that points to constant values, across all pending transaction types, and are ignored during the calculation + */ private static final Set COMMON_CONSTANT_FIELD_PATHS = Set.of(".value.ctor", ".hashNoSignature", ".signature.encoded.delegate"); + /** + * Field that points to constant values, for EIP-1559 and EIP-4844 pending transactions, and are ignored during the calculation + */ private static final Set EIP1559_EIP4844_CONSTANT_FIELD_PATHS = Sets.union(COMMON_CONSTANT_FIELD_PATHS, Set.of(".gasPrice")); + /** + * Field that points to constant values, for Frontier and Access List pending transactions, and are ignored during the calculation + */ private static final Set FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS = Sets.union(COMMON_CONSTANT_FIELD_PATHS, Set.of(".maxFeePerGas", ".maxPriorityFeePerGas")); + /** + * Field which value is dynamic and can only be calculated at runtime + */ private static final Set VARIABLE_SIZE_PATHS = Set.of( ".chainId", @@ -121,7 +174,7 @@ public void toSize() { System.out.println("Optional To size: " + size); - assertThat(size.sum()).isEqualTo(PendingTransaction.OPTIONAL_TO_MEMORY_SIZE); + assertThat(size.sum()).isEqualTo(OPTIONAL_TO_SIZE); } @Test @@ -146,7 +199,7 @@ public void payloadSize() { size.add(cl.instanceSize()); System.out.println("Base payload size: " + size); - assertThat(size.sum()).isEqualTo(PendingTransaction.PAYLOAD_BASE_MEMORY_SIZE); + assertThat(size.sum()).isEqualTo(PAYLOAD_SHALLOW_SIZE); } @Test @@ -180,39 +233,37 @@ public void chainIdSize() { gw.walk(maybeChainId); - assertThat(size.sum()).isEqualTo(PendingTransaction.OPTIONAL_CHAIN_ID_MEMORY_SIZE); + assertThat(size.sum()).isEqualTo(OPTIONAL_CHAIN_ID_SIZE); } @Test public void kgzCommitmentsSize() { blobsWithCommitmentsFieldSize( t -> t.getBlobsWithCommitments().get().getKzgCommitments(), - PendingTransaction.BASE_LIST_SIZE, - PendingTransaction.KZG_COMMITMENT_OR_PROOF_SIZE); + LIST_SHALLOW_SIZE, + KZG_COMMITMENT_OR_PROOF_SIZE); } @Test public void kgzProofsSize() { blobsWithCommitmentsFieldSize( t -> t.getBlobsWithCommitments().get().getKzgProofs(), - PendingTransaction.BASE_LIST_SIZE, - PendingTransaction.KZG_COMMITMENT_OR_PROOF_SIZE); + LIST_SHALLOW_SIZE, + KZG_COMMITMENT_OR_PROOF_SIZE); } @Test public void blobsSize() { blobsWithCommitmentsFieldSize( - t -> t.getBlobsWithCommitments().get().getBlobs(), - PendingTransaction.BASE_LIST_SIZE, - PendingTransaction.BLOB_SIZE); + t -> t.getBlobsWithCommitments().get().getBlobs(), LIST_SHALLOW_SIZE, BLOB_SIZE); } @Test public void versionedHashesSize() { blobsWithCommitmentsFieldSize( t -> t.getBlobsWithCommitments().get().getVersionedHashes(), - PendingTransaction.BASE_LIST_SIZE, - PendingTransaction.VERSIONED_HASH_SIZE); + LIST_SHALLOW_SIZE, + VERSIONED_HASH_SIZE); } private void blobsWithCommitmentsFieldSize( @@ -273,8 +324,7 @@ public void blobsWithCommitmentsSize() { System.out.println(rl.toPrintable()); System.out.println("BlobQuad size:" + rl.instanceSize()); - assertThat(cl.instanceSize() + rl.instanceSize()) - .isEqualTo(PendingTransaction.BLOBS_WITH_COMMITMENTS_SIZE); + assertThat(cl.instanceSize() + rl.instanceSize()).isEqualTo(BLOBS_WITH_COMMITMENTS_SIZE); } @Test @@ -300,7 +350,7 @@ public void pendingTransactionSize() { size.add(cl.instanceSize()); System.out.println("PendingTransaction size: " + size); - assertThat(size.sum()).isEqualTo(PendingTransaction.PENDING_TRANSACTION_MEMORY_SIZE); + assertThat(size.sum()).isEqualTo(PENDING_TRANSACTION_SHALLOW_SIZE); } @Test @@ -326,16 +376,18 @@ public void accessListSize() { final var optAL = txAccessList.getAccessList(); - final ClassLayout cl1 = ClassLayout.parseInstance(optAL); - System.out.println(cl1.toPrintable()); - System.out.println("Optional size: " + cl1.instanceSize()); + final ClassLayout optionalClassLayout = ClassLayout.parseInstance(optAL); + System.out.println(optionalClassLayout.toPrintable()); + System.out.println("Optional size: " + optionalClassLayout.instanceSize()); - final ClassLayout cl2 = ClassLayout.parseInstance(optAL.get()); - System.out.println(cl2.toPrintable()); - System.out.println("Optional + list size: " + (cl1.instanceSize() + cl2.instanceSize())); + final ClassLayout listClassLayout = ClassLayout.parseInstance(optAL.get()); + System.out.println(listClassLayout.toPrintable()); + System.out.println( + "Optional + list size: " + + (optionalClassLayout.instanceSize() + listClassLayout.instanceSize())); - assertThat(cl1.instanceSize() + cl2.instanceSize()) - .isEqualTo(PendingTransaction.OPTIONAL_ACCESS_LIST_MEMORY_SIZE); + assertThat(optionalClassLayout.instanceSize() + listClassLayout.instanceSize()) + .isEqualTo(OPTIONAL_ACCESS_LIST_SHALLOW_SIZE); final AccessListEntry ale = optAL.get().get(0); @@ -343,15 +395,14 @@ public void accessListSize() { System.out.println("AccessListEntry container size: " + aleSize); - assertThat(aleSize).isEqualTo(PendingTransaction.ACCESS_LIST_ENTRY_BASE_MEMORY_SIZE); + assertThat(aleSize).isEqualTo(ACCESS_LIST_ENTRY_SHALLOW_SIZE); final Bytes32 storageKey = ale.storageKeys().get(0); final ClassLayout cl4 = ClassLayout.parseInstance(storageKey); System.out.println(cl4.toPrintable()); System.out.println("Single storage key size: " + cl4.instanceSize()); - assertThat(cl4.instanceSize()) - .isEqualTo(PendingTransaction.ACCESS_LIST_STORAGE_KEY_MEMORY_SIZE); + assertThat(cl4.instanceSize()).isEqualTo(ACCESS_LIST_STORAGE_KEY_SIZE); } @Test @@ -372,16 +423,18 @@ public void codeDelegationListSize() { final var optCD = txDelegateCode.getCodeDelegationList(); - final ClassLayout cl1 = ClassLayout.parseInstance(optCD); - System.out.println(cl1.toPrintable()); - System.out.println("Optional size: " + cl1.instanceSize()); + final ClassLayout optionalClassLayout = ClassLayout.parseInstance(optCD); + System.out.println(optionalClassLayout.toPrintable()); + System.out.println("Optional size: " + optionalClassLayout.instanceSize()); - final ClassLayout cl2 = ClassLayout.parseInstance(optCD.get()); - System.out.println(cl2.toPrintable()); - System.out.println("Optional + list size: " + (cl1.instanceSize() + cl2.instanceSize())); + final ClassLayout listClassLayout = ClassLayout.parseInstance(optCD.get()); + System.out.println(listClassLayout.toPrintable()); + System.out.println( + "Optional + list size: " + + (optionalClassLayout.instanceSize() + listClassLayout.instanceSize())); - assertThat(cl1.instanceSize() + cl2.instanceSize()) - .isEqualTo(PendingTransaction.OPTIONAL_CODE_DELEGATION_LIST_MEMORY_SIZE); + assertThat(optionalClassLayout.instanceSize() + listClassLayout.instanceSize()) + .isEqualTo(OPTIONAL_CODE_DELEGATION_LIST_SHALLOW_SIZE); final CodeDelegation codeDelegation = optCD.get().get(0); @@ -389,14 +442,14 @@ public void codeDelegationListSize() { System.out.println("CodeDelegation container size: " + cdSize); - assertThat(cdSize).isEqualTo(PendingTransaction.CODE_DELEGATION_ENTRY_MEMORY_SIZE); + assertThat(cdSize).isEqualTo(CODE_DELEGATION_ENTRY_SIZE); } @Test public void baseEIP1559AndEIP4844TransactionMemorySize() { Transaction txEip1559 = createEIP1559Transaction(1, KEYS1, 10); assertThat(baseTransactionMemorySize(txEip1559, EIP1559_EIP4844_CONSTANT_FIELD_PATHS)) - .isEqualTo(PendingTransaction.EIP1559_AND_EIP4844_SHALLOW_MEMORY_SIZE); + .isEqualTo(EIP1559_AND_EIP4844_SHALLOW_SIZE); } @Test @@ -404,7 +457,7 @@ public void baseFrontierAndAccessListTransactionMemorySize() { final Transaction txFrontier = createTransaction(TransactionType.FRONTIER, 1, Wei.of(500), 0, KEYS1); assertThat(baseTransactionMemorySize(txFrontier, FRONTIER_ACCESS_LIST_CONSTANT_FIELD_PATHS)) - .isEqualTo(PendingTransaction.FRONTIER_AND_ACCESS_LIST_SHALLOW_MEMORY_SIZE); + .isEqualTo(FRONTIER_AND_ACCESS_LIST_SHALLOW_SIZE); } private long baseTransactionMemorySize(final Transaction tx, final Set constantFields) { @@ -509,6 +562,15 @@ private long sizeOfField(final Object container, final String... excludePaths) { return size.sum(); } + /** + * Utility method useful for producing a heap dump when calculating the memory size of a new + * object. Note that the file is not overwritten, so you need to remove it to create a new heap + * dump. + * + * @param filePath where to save the heap dump + * @param live true to only include live objects + * @throws IOException if any errors happen during the saving + */ @SuppressWarnings("unused") private static void dumpHeap(final String filePath, final boolean live) throws IOException { MBeanServer server = ManagementFactory.getPlatformMBeanServer();