/** * Dumps heap with a name with a human-readable timestamp to the Mesos sandbox, if environment variable * {@code MESOS_SANDBOX} is defined, or to the system temporary directory otherwise. * Logs where the heap dump will be written. * Logs a warning if there was a problem preventing the heap dump from being successfully created. */ public static void dumpHeap() { dumpHeap(getHeapDumpPath()); }
@Nonnull private static Path getHeapDumpPath() { final String filename = String.format("heapdump-%s.hprof", Instant.now()); return getHeapDumpDir().resolve(filename); }
private void refreshNmt() { final Instant now = Instant.now(); if (now.isBefore(lastRefresh.plus(REFRESH_PERIOD))) { return; } nmt = Memory.getNmt(); Preconditions.checkNotNull(nmt); lastRefresh = now; refreshCategories(); }
@Override public String toString() { final int rows = categories.size() + 2; final List<String> col1 = new ArrayList<>(rows); col1.add("Name"); col1.add("Total"); col1.addAll(categories.keySet()); final int colWidth1 = maxLength(col1); final List<String> col2 = new ArrayList<>(rows); col2.add("Reserved"); col2.add(Memory.formatBytes(total.reserved)); categories.keySet().forEach(name -> col2.add(Memory.formatBytes(categories.get(name).reserved))); final int colWidth2 = maxLength(col2); final List<String> col3 = new ArrayList<>(rows); col3.add("Committed"); col3.add(Memory.formatBytes(total.committed)); categories.keySet().forEach(name -> col3.add(Memory.formatBytes(categories.get(name).committed))); final int colWidth3 = maxLength(col3); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < rows; i++) { sb.append(pad(col1, colWidth1, i)).append(" "); sb.append(pad(col2, colWidth2, i)).append(" "); sb.append(pad(col3, colWidth3, i)).append('\n'); } return sb.toString(); }
/** * Kicks off a poller thread that will periodically log human-readable NMT. * Uses {@link #formatNmt()} internally, and so also requires JVM argument * {@code -XX:NativeMemoryTracking=summary}. * @param interval The interval with which to poll and log NMT. * @return {@link NmtCloseable} that you can use to terminate the poller. */ public static NmtCloseable pollNmt(final Duration interval) { final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor("nmt-poller"); final long intervalNanos = TimeUnit.SECONDS.toNanos(interval.getSeconds()) + TimeUnit.NANOSECONDS.toNanos(interval.getNano()); final Runnable command = () -> { final String summary = formatNmt(); // null return values will cause a warning to get logged without us needing to do so. if (summary != null) { LOG.info("\n" + summary); } }; exec.scheduleWithFixedDelay(command, 0, intervalNanos, TimeUnit.NANOSECONDS); return exec::shutdownNow; }
@VisibleForTesting @Nonnull static Path getHeapDumpDir() { final String envName = "MESOS_SANDBOX"; final String envVar; try { envVar = getenv.apply(envName); } catch (SecurityException e) { LOG.warn("error getting environment variable {}", envName, e); return getTmpDir(); } if (envVar == null) { return getTmpDir(); } return Paths.get(envVar); }
public static void main(String[] args) { Memory.dumpHeap(); } }
/** * Dumps heap to the specified path. * Logs where the heap dump will be written. * Logs a warning if there was a problem preventing the heap dump from being successfully created. * @param path Where to put the heap dump. */ public static void dumpHeap(final Path path) { LOG.info("writing heap dump to {}", path); final HotSpotDiagnosticMXBean bean = getBean(HotSpotDiagnosticMXBean.class); if (bean == null) { return; } try { bean.dumpHeap(path.toString(), true); } catch (IOException e) { LOG.warn("error writing heap dump", e); } }
public static void main(String[] args) throws InterruptedException { final Duration aSec = Duration.ofSeconds(1); final Duration toSleep = Duration.ofSeconds(3); try (final Memory.NmtCloseable c = Memory.pollNmt(aSec)) { Thread.sleep(toSleep.toMillis()); } } }
@Test public void formatBytes3() { Assert.assertEquals(Memory.formatBytes(3 * 1024 * 1024), "3.00 MiB"); } }
public static void main(String[] args) { System.out.println("VM output:"); System.out.print(Nmt.invoke()); System.out.println("our parsed/formatted version:"); System.out.print(Memory.formatNmt()); } }
@Test public void dumpHeapTmpDirDefault() { final String propName = "java.io.tmpdir"; final String old = System.clearProperty(propName); if (old == null) { throw new AssertionError("we were going to be the one to kill this"); } Assert.assertEquals(Memory.getTmpDir().toString(), Memory.DEFAULT_TMP_PATH); System.setProperty(propName, old); }
@Test public void formatBytes1() { Assert.assertEquals(Memory.formatBytes(1024), "1.00 KiB"); }
public synchronized void register() { nmt = Memory.getNmt(); if (nmt == null) { LOG.info("got null NMT info; not registering any metrics"); return; } lastRefresh = Instant.now(); refreshCategories(); if (registeredMetrics.isEmpty()) { LOG.warn("Didn't find any NMT metrics to register!"); } registerGauges("total", () -> nmt.total); }
/** * @see NmtTest */ @Test public void formatNmt() { Assert.assertNotNull(Memory.formatNmt()); }
@Test public void getHeapDumpDirMesos() { final String testValue = "/bing/bing/bam/bam"; final Function<String, String> old = Memory.getenv; Memory.getenv = name -> { if (name.equals("MESOS_SANDBOX")) { return testValue; } throw new AssertionError("unexpected environment inspection"); }; Assert.assertEquals(Memory.getHeapDumpDir().toString(), testValue); Memory.getenv = old; }
@Test public void formatBytes2() { Assert.assertEquals(Memory.formatBytes(20), "20 B"); }
/** * @see NmtTest */ @Test public void getNmt() { Assert.assertNotNull(Memory.getNmt()); }