The Memory Estimator

What is the size of a byte[] array in Java?

Came across this blog post by Daniel Lemire. It’s not his most interesting or informative post, but made me remember a little utility I wrote many years ago. MemoryEstimator is a tool to estimate the memory footprint of any Java type. (It’s part of ojAlgo.) Just had to verify if its estimates are aligned with the numbers presented in that blog post. In that post there is a table of estimated memory usage for byte arrays of different sizes. These are the numbers:

size of the arrayestimated memory usage
016 bytes
124 bytes
224 bytes
324 bytes
424 bytes
524 bytes
624 bytes
724 bytes
824 bytes
932 bytes

Now, let’s see if MemoryEstimator produces the same estimates.

Example/Test Code

TheMemoryEstimator.java
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.util.OptionalDouble;

import org.ojalgo.OjAlgoUtils;
import org.ojalgo.machine.JavaType;
import org.ojalgo.machine.MemoryEstimator;
import org.ojalgo.netio.BasicLogger;

/**
 * A tiny example demonstrating the use of the MemoryEstimator utility.
 *
 * @see https://www.ojalgo.org/2022/12/the-memory-estimator/
 */
public class TheMemoryEstimator {

    public static void main(final String[] args) {

        BasicLogger.debug();
        BasicLogger.debug(TheMemoryEstimator.class);
        BasicLogger.debug(OjAlgoUtils.getTitle());
        BasicLogger.debug(OjAlgoUtils.getDate());
        BasicLogger.debug();

        /*
         * To estimate the memory footprint of an array of any Java type, you just specify which type and the
         * length of the array, and then call 'estimateArray'.
         */
        BasicLogger.debug();
        BasicLogger.debug("Size of byte[] of different lengths");
        BasicLogger.debug("===================================");

        for (int i = 0; i < 10; i++) {

            long estimate = MemoryEstimator.estimateArray(byte.class, i);

            BasicLogger.debug("byte[{}] == {} bytes", i, estimate);
        }

        /*
         * There is also an enum named JavaType that enumerates Java's basic types.
         */
        BasicLogger.debug();
        BasicLogger.debug("Memory footprint of Java's basic types");
        BasicLogger.debug("======================================");

        for (JavaType type : JavaType.values()) {
            BasicLogger.debug("{} {} bytes", type.getJavaClass().getSimpleName(), type.memory());
            BasicLogger.debug(1, "{} bytes when wrapped/boxed in a class", type.estimateSizeOfWrapperClass());
        }

        /*
         * It's also possible to estimate the size of any Java object.
         */
        BasicLogger.debug();
        BasicLogger.debug("Memory footprint of some specific types");
        BasicLogger.debug("=======================================");
        BasicLogger.debug("BigDecimal     == {} bytes", MemoryEstimator.estimateObject(BigDecimal.class));
        BasicLogger.debug("LocalDate      == {} bytes", MemoryEstimator.estimateObject(LocalDate.class));
        BasicLogger.debug("Instant        == {} bytes", MemoryEstimator.estimateObject(Instant.class));
        BasicLogger.debug("OptionalDouble == {} bytes", MemoryEstimator.estimateObject(OptionalDouble.class));

        /*
         * Estimating the size of complex data types containing arrays, collections and multiple references to
         * other objects is meaningless (the way MemoryEstimator works). Even with the few examples above
         * there's a problem. BigDecimal contains a reference to a BigInteger, but the estimate only includes
         * the size of the reference to that instance – not the size of the BigInteger instance itself.
         */
    }

}

Console Output

class TheMemoryEstimator
ojAlgo
2022-12-01


Size of byte[] of different lengths
===================================
byte[0] == 16 bytes
byte[1] == 24 bytes
byte[2] == 24 bytes
byte[3] == 24 bytes
byte[4] == 24 bytes
byte[5] == 24 bytes
byte[6] == 24 bytes
byte[7] == 24 bytes
byte[8] == 24 bytes
byte[9] == 32 bytes

Memory footprint of Java's basic types
======================================
boolean 1 bytes
	16 bytes when wrapped/boxed in a class
byte 1 bytes
	16 bytes when wrapped/boxed in a class
char 2 bytes
	16 bytes when wrapped/boxed in a class
double 8 bytes
	24 bytes when wrapped/boxed in a class
float 4 bytes
	16 bytes when wrapped/boxed in a class
int 4 bytes
	16 bytes when wrapped/boxed in a class
long 8 bytes
	24 bytes when wrapped/boxed in a class
Object 4 bytes
	16 bytes when wrapped/boxed in a class
short 2 bytes
	16 bytes when wrapped/boxed in a class

Memory footprint of some specific types
=======================================
BigDecimal     == 40 bytes
LocalDate      == 24 bytes
Instant        == 24 bytes
OptionalDouble == 24 bytes