import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; import java.nio.file.Files; import java.nio.file.Path; /** * A deliberately boring allocation workload, used to ask one question: what does the switch from * Serial to G1 cost (or save) on a machine that used to get Serial? * *
It allocates small objects as fast as it can, keeps roughly 1% of them alive in a ring buffer * (so the collector has real work to do, not just an empty young generation), and reports wall * time, collection count and time, the slowest single batch (a rough stand-in for the worst * stall an application thread saw), and the process's peak resident memory from /proc. * *
Timing numbers are indicative, not a benchmark: one process, one run, a shared machine. * The point is the SHAPE of the difference. See docs/02-g1-default.md. */ public class Workload { record Item(long id, String label, byte[] payload) {} public static void main(String[] args) throws Exception { int batches = args.length > 0 ? Integer.parseInt(args[0]) : 400; int perBatch = 50_000; Item[] ring = new Item[100_000]; int ringPos = 0; long checksum = 0; long slowestBatchNanos = 0; long start = System.nanoTime(); for (int b = 0; b < batches; b++) { long t0 = System.nanoTime(); for (int i = 0; i < perBatch; i++) { long id = (long) b * perBatch + i; Item item = new Item(id, "item-" + id, new byte[64 + (int) (id & 63)]); checksum += item.payload().length; if (id % 100 == 0) { ring[ringPos] = item; ringPos = (ringPos + 1) % ring.length; } } slowestBatchNanos = Math.max(slowestBatchNanos, System.nanoTime() - t0); } long elapsedMs = (System.nanoTime() - start) / 1_000_000; long gcCount = 0, gcMs = 0; for (GarbageCollectorMXBean gc : ManagementFactory.getGarbageCollectorMXBeans()) { gcCount += Math.max(0, gc.getCollectionCount()); gcMs += Math.max(0, gc.getCollectionTime()); } System.out.printf("allocated objects = %,d (checksum %d)%n", (long) batches * perBatch, checksum); System.out.printf("wall time = %d ms%n", elapsedMs); System.out.printf("gc count / time = %d / %d ms%n", gcCount, gcMs); System.out.printf("slowest batch = %d ms%n", slowestBatchNanos / 1_000_000); System.out.printf("peak RSS = %d MB%n", peakRssKb() / 1024); } /** VmHWM is the high-water mark of the resident set, in kB. */ static long peakRssKb() throws Exception { for (String line : Files.readAllLines(Path.of("/proc/self/status"))) { if (line.startsWith("VmHWM:")) { return Long.parseLong(line.replaceAll("\\D+", "")); } } return -1; } }