A jam garbage collector for the JVM
jam-vm
This project adapts jam to collect Java objects on HotSpot and Native Image, with both Java reference processing and GHC-style generalized weak pointers. The intended consumer is thc: Haskell running through Truffle/Graal, with its closures in the host heap.
Using Jam
First, build the patched JDK. Then select Jam with that JVM:
java -Xshare:off -Xms256m -Xmx256m \
-XX:+UnlockExperimentalVMOptions -XX:+UseJamGC -Xlog:gc \
-jar application.jarKeep -Xms and -Xmx equal. Ordinary Java code continues to use its existing reference classes. Code that needs generalized weak associations can use jam.vm.Weak from the Java/JNI API.
For a native executable, build with native-image --gc=jam. The Native Image guide covers heap sizing, deployment and the same weak API without a JVM at runtime.
Weak associations
A weak association connects a key to a value and an optional finalizer. The value may refer back to its key without keeping the association alive:
weak association: key ⇒ value
▲ │
└──────┘
If something else keeps the key alive, the value stays available. Otherwise the association dies, even though its value could have led us back to the key. The weak-pointer guide explains the fixed point behind that rule and what happens when finalizers resurrect objects.
After adding the API to your runtime, install an association:
import jam.vm.Weak;
Weak.checkAvailable();
long token = Weak.create(key, value, () -> releaseResource());
Object result = Weak.deref(token);Finalizers run when a caller pumps the shared queue:
int completed = Weak.pump();A finalizer is a JVM Runnable. It may enter whatever guest context it needs; jam-vm does not need to know which context supplied it. Any caller can pump. See integrating thc for build instructions, explicit finalization and the claim/completion protocol.
Finding your way around
The build guide covers the source pins and native libraries. Supported configurations lists current limits. Start there if you want to run the collector or embed the weak API.
For work on the collector itself, heap architecture derives the compressed-oop encoding from jam's cell offsets. The HotSpot integration describes the C++26/C++14 boundary, roots, barriers and collection phases.
Contact Information
Contributions and bug reports are welcome!
Please feel free to contact me through GitHub.
-Edward Kmett