package bench; import java.io.BufferedWriter; import java.io.IOException; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryPoolMXBean; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.List; /** * Memory sampling for the MegaMek density benchmark. * *
Three numbers matter and they are not interchangeable: *
One System.gc() is not enough under G1: weakly reachable objects and * humongous regions routinely survive the first pass. Three passes with a * pause between them gets close enough to the true live set that the * per-game delta is trustworthy. */ public static long liveHeapKb() { for (int i = 0; i < 3; i++) { System.gc(); try { Thread.sleep(250L); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } Runtime rt = Runtime.getRuntime(); return (rt.totalMemory() - rt.freeMemory()) / 1024L; } /** Cheap sample: no forced GC, safe to call on a tight polling loop. */ public void sample(String label, int gamesStarted, int gamesLive, int totalRounds) { write(label, gamesStarted, gamesLive, totalRounds, -1L); } /** Expensive sample: forces GC first so liveHeapKb is meaningful. */ public void checkpoint(String label, int gamesStarted, int gamesLive, int totalRounds) { write(label, gamesStarted, gamesLive, totalRounds, liveHeapKb()); } private void write(String label, int gamesStarted, int gamesLive, int totalRounds, long liveHeapKb) { double elapsedSec = (System.nanoTime() - startNanos) / 1_000_000_000.0; long heapUsedKb = memoryBean.getHeapMemoryUsage().getUsed() / 1024L; long heapCommittedKb = memoryBean.getHeapMemoryUsage().getCommitted() / 1024L; long nonHeapUsedKb = memoryBean.getNonHeapMemoryUsage().getUsed() / 1024L; String row = String.format("%.1f,%s,%d,%d,%d,%d,%d,%d,%d,%d,%d%n", elapsedSec, label, gamesStarted, gamesLive, totalRounds, rssKb(), heapUsedKb, heapCommittedKb, nonHeapUsedKb, metaspaceKb(), liveHeapKb); try (BufferedWriter out = Files.newBufferedWriter(csv, StandardCharsets.UTF_8, StandardOpenOption.APPEND)) { out.write(row); } catch (IOException e) { System.err.println("[sampler] write failed: " + e.getMessage()); } if (liveHeapKb >= 0) { System.out.printf("[%6.1fs] %-22s games=%d live=%d rounds=%d rss=%dMB liveHeap=%dMB meta=%dMB%n", elapsedSec, label, gamesStarted, gamesLive, totalRounds, rssKb() / 1024, liveHeapKb / 1024, metaspaceKb() / 1024); } } }