Maven Build Cache Extension

One of the advantages Gradle had over Maven was build caching.

Thanks to Maven Cache Build Extension  you can also get build caching for maven builds too.

How to set this up

On the top level of your maven project add

.mvn folder

Within the mvn folder add extensions.xml  and maven-build-cache-config.xml

Example

 

The contents of extensions.xml should be something like this

<extensions>
    <extension>
        <groupId>org.apache.maven.extensions</groupId>
        <artifactId>maven-build-cache-extension</artifactId>
        <version>1.2.1</version>
    </extension>
</extensions>

 

The contents of  maven-build-cache-config.xml should be like this from the template provided by in this  In the Getting Started page for Maven Build Cache Extension 

(link for the template config can be found here)

Note the default config has remote enabled, which is annoying default if you just want to get local build cache working first.

So here are few adjustments I made to the template maven-build-cache-config.xml

(yellow commented out ,  green additional config added)

 

 

Also for slimplicity I also comment out the global section with in the input section of the template

 

Now when you run your maven build (the second time), you should see it skipping various plugins as it uses the cached results instead

 

Where is the cached build stored?  By default in the same folder your your m2 repository resides

 

 

 

 

 

 

 

 

Experimenting with Valhalla Early Access Build 26-jep401ea2+1-1 (2025/10/10)

 

A new build of Valhalla has been made available on https://jdk.java.net/valhalla/ this version is built on top Java 26 early build.

It’s been a while since I tried to the previous Valhalla Early access in 2022

A lot has has changed since then.

In the previous version they had concept of value (without identity) and primitive class (without identity and not nullable)

Now they have simplified to value class (without identity)

Whether a value can be nullable is or not, will be delivered separately by this JEP draft: Null-Restricted Value Class Types (Preview)

Reference Code – No Value class


public class Main {
    static void main() {
        long start = System.currentTimeMillis();
        int length = 10_000_000;
        Point3D[] myArray = new Point3D[length];
        for (int i = 0; i &lt; myArray.length; i++) {
            myArray[i]=new Point3D(0f, 0f, 0f);
        }
        System.out.println("Print last value of array : "+myArray[length-1]);
        Runtime.getRuntime().gc();
        printMemoryUsage();
        System.out.println("Array length : "+myArray.length);
        System.out.println("Total time "+(System.currentTimeMillis() - start)+ " ms");
    }
    private static void printMemoryUsage() {
        System.out.println("MB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024*1024));
    }
    static class Point3D {
        private float x ;
        private  float y ;
        private  float z ;
        public Point3D(float x, float y, float z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }
        @Override
        public String toString() {
            return "Point3D{" +
                    "x=" + x +
                    ", y=" + y +
                    ", z=" + z +
                    '}';
        }
    }
}

 

If I run this on my machine I get this output

Print last value of array : Point3D{x=0.0, y=0.0, z=0.0}
MB: 269.9514617919922
Array length : 10000000
Total time 182 ms

 

Now if I do the same using Value class (make Point3D value class)

 


public class Main {
    static void main() {
        long start = System.currentTimeMillis();
        int length = 10_000_000;
        Point3D[] myArray = new Point3D[length];
        for (int i = 0; i &lt; myArray.length; i++) {
            myArray[i]=new Point3D(0f, 0f, 0f);
        }
        System.out.println("Print last value of array : "+myArray[length-1]);
        Runtime.getRuntime().gc();
        printMemoryUsage();
        System.out.println("Array length : "+myArray.length);
        System.out.println("Total time "+(System.currentTimeMillis() - start)+ " ms");
    }
    private static void printMemoryUsage() {
        System.out.println("MB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024*1024));
    }
    static value class Point3D {
        private float x ;
        private  float y ;
        private  float z ;
        public Point3D(float x, float y, float z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }
        @Override
        public String toString() {
            return "Point3D{" +
                    "x=" + x +
                    ", y=" + y +
                    ", z=" + z +
                    '}';
        }
    }
}

Print last value of array : Point3D{x=0.0, y=0.0, z=0.0}
MB: 269.80834197998047
Array length : 10000000
Total time 224 ms

Oh dear 🙁 actually ran slower using value class !

 

Currently (in this build for now) value class is restricted to 64bit for flattening.

The point3d class has 3 floats = 32 * 3 = 96 bits

In additional there is also an extra bit also added to keep track of whether the value is null or not.

So it’s actually (32 * 3) +1 = 97 bits

 

Why 64bit restriction for flattening, apparently that is to align with size of registers which are 64 bits, otherwise if you need multiple registers, you are in danger of tearing – where threads might be able to read an inconsistent value.

 

However, in the EA build there is an option to create an array of value classes where you can accept tearning might occur and also specify the values cannot be null

 

Replace these lines


for (int i = 0; i &lt; myArray.length; i++) {
    myArray[i]=new Point3D(0f, 0f, 0);
}

 

with this instead (but note this using a jdk internal class ) so you will need to use this additional command line flags

–add-exports java.base/jdk.internal.value=ALL-UNNAMED –enable-preview


Point3D[] myArray = (Point3D[]) ValueClass.newNullRestrictedNonAtomicArray(Point3D.class, 10_000_000, new Point3D(0f, 0f, 0f));

 

Full Code (Enabling Null-Restriction and Non-Atomicity )


import jdk.internal.value.ValueClass;

public class Main {
    static void main() {
        long start = System.currentTimeMillis();
        int length = 10_000_000;
        Point3D[] myArray = (Point3D[]) ValueClass.newNullRestrictedNonAtomicArray(Point3D.class, 10_000_000, new Point3D(0f, 0f, 0f));
        System.out.println("Print last value of array : "+myArray[length-1]);
        Runtime.getRuntime().gc();
        printMemoryUsage();
        System.out.println("Array length : "+myArray.length);
        System.out.println("Total time "+(System.currentTimeMillis() - start)+ " ms");
    }
    private static void printMemoryUsage() {
        System.out.println("MB: " + (double) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024*1024));
    }
    static value class Point3D {
        private float x ;
        private  float y ;
        private  float z ;
        public Point3D(float x, float y, float z) {
            this.x = x;
            this.y = y;
            this.z = z;
        }
        @Override
        public String toString() {
            return "Point3D{" +
                    "x=" + x +
                    ", y=" + y +
                    ", z=" + z +
                    '}';
        }
    }
}

With above the output is now

Print last value of array : Point3D{x=0.0, y=0.0, z=0.0}
MB: 40.89228820800781
Array length : 10000000
Total time 109 ms

🙂

Wow!! From 270 mb we went down to 41 mb ! a huge reduction in memory usage!

Also the execution time was reduced from 182ms to 109ms

 

Hopefully this will be promoted from preview to something that ships in Java soon. Can’t wait!

Heap Dump

To get a heap dump of an existing application you need to know the PID of your java process.

To do this, you can use the jps command

jps -l

So for above, I can see the PID for the process is 5776

Once you know your PID you can use the jcmd to generate the heap dump

jcmd <pid> GC.heap_dump <file-path>

For above PID I can do


jcmd 5776 GC.heap_dump c:/temp/dump.hprof

To open the the heap dump, you can use YourKit or Open source tools such as Eclipse MAT tool

Using Eclipse MAT Tool we can open the Heap dump

Using the Eclipse MAT tool you can see the drill in the pie chat to list Objects and to see the incoming references, see the retain size of objects, see the paths to GC Root. MAT tool also has leak hunter tool to try to find problem areas.