Created
February 1, 2021 19:20
-
-
Save krasa/52a8325dbe95d549fcb246ba8693494e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.company; | |
import javax.management.MBeanServer; | |
import java.lang.management.ManagementFactory; | |
import java.lang.reflect.Method; | |
public class Main { | |
private ThreadLocal<Foo> threadLocal = new ThreadLocal<>(); | |
public static void main(String[] args) { | |
Main main = new Main(); | |
main.foo(); | |
} | |
void foo() { | |
String file = "HeapDump-" + System.currentTimeMillis() + ".hprof"; | |
leak(); | |
System.gc(); | |
new HeapDump().dumpHeap(file, true); | |
} | |
private void leak() { | |
Foo value = new Foo(); | |
threadLocal.set(value); | |
// threadLocal = null; | |
// threadLocal.remove(); | |
threadLocal = new ThreadLocal<>(); | |
threadLocal.remove(); | |
System.gc(); | |
System.err.println(new byte[10_000_000]); | |
System.gc(); | |
System.err.println(new byte[10_000_000]); | |
System.gc(); | |
} | |
public static class Foo { | |
byte[] b = new byte[10_000_000]; | |
} | |
@SuppressWarnings("restriction") | |
public static class HeapDump { | |
// This is the name of the HotSpot Diagnostic MBean | |
private static final String HOTSPOT_BEAN_NAME = | |
"com.sun.management:type=HotSpotDiagnostic"; | |
// field to store the hotspot diagnostic MBean | |
private static volatile Object hotspotMBean; | |
/** | |
* Call this method from your application whenever you | |
* want to dump the heap snapshot into a file. | |
* | |
* @param fileName name of the heap dump file | |
* @param live flag that tells whether to dump | |
* only the live objects | |
*/ | |
static void dumpHeap(String fileName, boolean live) { | |
// initialize hotspot diagnostic MBean | |
initHotspotMBean(); | |
try { | |
Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); | |
Method m = clazz.getMethod("dumpHeap", String.class, boolean.class); | |
m.invoke(hotspotMBean, fileName, live); | |
} catch (RuntimeException re) { | |
throw re; | |
} catch (Exception exp) { | |
throw new RuntimeException(exp); | |
} | |
} | |
// initialize the hotspot diagnostic MBean field | |
private static void initHotspotMBean() { | |
if (hotspotMBean == null) { | |
synchronized (HeapDump.class) { | |
if (hotspotMBean == null) { | |
hotspotMBean = getHotspotMBean(); | |
} | |
} | |
} | |
} | |
// get the hotspot diagnostic MBean from the | |
// platform MBean server | |
private static Object getHotspotMBean() { | |
try { | |
Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean"); | |
MBeanServer server = ManagementFactory.getPlatformMBeanServer(); | |
Object bean = | |
ManagementFactory.newPlatformMXBeanProxy(server, | |
HOTSPOT_BEAN_NAME, clazz); | |
return bean; | |
} catch (RuntimeException re) { | |
throw re; | |
} catch (Exception exp) { | |
throw new RuntimeException(exp); | |
} | |
} | |
public static void main(String[] args) { | |
// default heap dump file name | |
String fileName = "heap.bin"; | |
// by default dump only the live objects | |
boolean live = true; | |
// simple command line options | |
switch (args.length) { | |
case 2: | |
live = args[1].equals("true"); | |
case 1: | |
fileName = args[0]; | |
} | |
// dump the heap | |
dumpHeap(fileName, live); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment