Lazy Diary @ Hatena Blog

PowerShell / Java / miscellaneous things about software development, Tips & Gochas. CC BY-SA 4.0/Apache License 2.0

Validate memory consumption in a JUnit test case

For load test

If you want to run a load test in a JUnit test case and get maximum memory consumption or GC count as a Java variable, the way to do it doesn't seem to be.

For memory consumption of whole Java VM

If you want to run some tests and measure memory consumption of the whole Java VM, you can use Runtime#totalMemory() and Runtime#freeMemory() like this *1:

    static long initialMemoryConsumption;

    @BeforeAll
    static void recordInitialMemoryConsumption() {
        initialMemoryConsumption = getMemoryConsumption();
    }

    @AfterAll
    static void measureWholeMemoryConsumption() {
        System.out.println(getMemoryConsumption() - initialMemoryConsumption);
    }

    static long getMemoryConsumption() {
        Runtime runtime = Runtime.getRuntime();
        runtime.gc();
        return runtime.totalMemory() - runtime.freeMemory();
    }

For memory consumption of an object

If you want to measure rough memory consumption of a specific object in a test (for example, validate memory consumption is  O(n) and not  O(n^{2}) , or validate all the caches are invalidated), you can serialize the object into a byte array and measure the length of it.

    static int getMemoryConsumption(Serializable obj) throws IOException {
        try (
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream out = new ObjectOutputStream(bos);
                ) {
            out.writeObject(obj);
            out.flush();
            byte[] bytes = bos.toByteArray();
            return bytes.length;
        }
    }

    @Test
    void memoryConsumptionTest() throws IOException {
        ...
        assertTrue(getMemoryConsumption(someObject) < 500);
    }
  • You cannot use Runtime#totalMemory() and Runtime#freeMemory() for this purpose, because the whole memory consumption of Java VM reduces in a test case (memory consumption could seem like a minus value).
  • The measured object should implement the Serializable interface. If it doesn't, you have to add the interface at runtime with the Java instrumentation API and a library like Javassist *2.
  • The actual length of the byte array (< 500 in the above example) should be measured in the test environment before writing a test case.